ORA-00054: ทรัพยากรไม่ว่างและได้รับโดย NOWAIT ที่ระบุหรือหมดเวลา


193

เหตุใดฉันจึงได้รับข้อผิดพลาดฐานข้อมูลนี้เมื่อฉันอัพเดตตาราง

ข้อผิดพลาดที่บรรทัดที่ 1: ORA-00054: ทรัพยากรไม่ว่างและได้รับพร้อมกับ NOWAIT ที่ระบุหรือหมดเวลาหมดอายุ


22
โดยทั่วไปแล้วจะช่วยได้หากคุณโพสต์ข้อความที่นำไปสู่ข้อผิดพลาด
Gary Myers

คำตอบ:


222

ตารางของคุณถูกล็อคโดยข้อความค้นหาบางส่วนแล้ว ตัวอย่างเช่นคุณอาจดำเนินการ "select for update" และยังไม่ได้ยืนยัน / ย้อนกลับและเรียกใช้คิวรีแบบเลือกอื่น ทำการคอมมิต / ย้อนกลับก่อนที่จะดำเนินการค้นหาของคุณ


47
ฉันจะเพิ่ม 'ในเซสชั่นอื่น' ที่ สถานการณ์สมมติทั่วไปอย่างหนึ่งคือคุณได้ทดสอบการอัปเดตในเครื่องมือพูด SQL Developer หรือ Toad แล้วลองเรียกใช้งานที่อื่นในขณะที่เซสชันแรกยังคงล็อคอยู่ ดังนั้นคุณต้องยอมรับ / ย้อนกลับเซสชันอื่นก่อนจึงจะสามารถเรียกใช้การอัปเดตอีกครั้งได้
Alex Poole

1
ส่วนใหญ่ DML (แทรก / ลบ / อัปเดต) แทนที่จะเป็นแบบสอบถาม และในเซสชั่นอื่น เพียงเพราะคนที่ถามว่าดูเหมือนจะเป็นมือใหม่คำตอบอาจถูกต้อง แต่คุณไม่สามารถกระทำในนามของผู้ใช้รายอื่นในระบบการผลิต
Arturo Hernandez

4
สิ่งที่ทำให้ฉันมีปัญหาคือในคางคก: เพื่อนร่วมงานอยู่ในตารางเดียวกับที่ฉันเคยเมื่อฉันต้องการที่จะลบแถวและดังนั้นฉันจึงไม่สามารถลบได้ เมื่อเขาเปลี่ยนเป็นตารางอื่นฉันสามารถลบแถวได้ มันอาจช่วยให้ใครบางคนออกมี แต่นี่เป็นเพียงถ้าคุณทำงานกับคางคกภายในตารางและไม่ใช้สำหรับแบบสอบถาม
DatRid

เพิ่งเกิดขึ้นบนเซิร์ฟเวอร์ staging ของเรา (Spring application บน WebSphere) วิธีแก้ไขคือการแยกสคริปต์อัปเดตฐานข้อมูล "เสาหิน" ออกเป็นชิ้นเล็ก ๆ โดยการย้ายคำสั่งที่ทำให้เกิดข้อผิดพลาดไปยังบริการอัปเดตแยกต่างหากซึ่งใช้ธุรกรรมแยกต่างหาก: @Transactional (propagation = Propagation.REQUIRES_NEW)
actc

103

จากที่นี่ORA-00054: ทรัพยากรไม่ว่างและได้รับโดยระบุ NOWAIT

นอกจากนี้คุณยังสามารถค้นหา sql, ชื่อผู้ใช้, เครื่อง, ข้อมูลพอร์ตและไปยังกระบวนการจริงที่เก็บการเชื่อมต่อ

SELECT O.OBJECT_NAME, S.SID, S.SERIAL#, P.SPID, S.PROGRAM,S.USERNAME,
S.MACHINE,S.PORT , S.LOGON_TIME,SQ.SQL_FULLTEXT 
FROM V$LOCKED_OBJECT L, DBA_OBJECTS O, V$SESSION S, 
V$PROCESS P, V$SQL SQ 
WHERE L.OBJECT_ID = O.OBJECT_ID 
AND L.SESSION_ID = S.SID AND S.PADDR = P.ADDR 
AND S.SQL_ADDRESS = SQ.ADDRESS;

5
ฉันต้องลบ s.port ออกจากข้อความค้นหา แต่ให้ฉันหาผู้กระทำผิด
Sibster

ล็อคชั่วคราว ดังนั้นหากมีการแทรกเกิดขึ้นคุณจะต้องทำทันที มันจะไม่ปรากฏในแบบสอบถามนี้ คุณยังสามารถได้รับข้อผิดพลาดหากคุณออก 'DDL' ในขณะที่การทำธุรกรรมเปิดอยู่ ดูโพสต์ของฉันด้านล่างนี่เป็นเรื่องง่ายที่จะหลีกเลี่ยง
บ๊อบ

4
ฉันมีปัญหาเดียวกันกับ OP แต่ฉันไม่เห็นตารางใด ๆ ที่คุณพูดถึง (เลือก * จาก V $ LOCKED_OBJECT ตัวอย่างเช่นคืน ORA-00942: ไม่มีตารางหรือมุมมอง) ความคิดใด ๆ
random_forest_fanatic

3
คุณอาจมีสิทธิ์ไม่เพียงพอที่จะดูมุมมองการจัดการ
njplumridge

ติดตามS.Portปัญหา: เอกสาร 11.2 ที่กล่าวถึงPortเป็นฟิลด์ในV$Sessionแต่สำหรับฉันที่ใช้ 11.1 S.Portนั้นไม่ถูกต้อง มันเพิ่มเข้ามาสำหรับ 11.2 บางที?

64

โปรดฆ่าเซสชัน Oracle

ใช้แบบสอบถามด้านล่างเพื่อตรวจสอบข้อมูลเซสชั่นที่ใช้งาน

SELECT
    O.OBJECT_NAME,
    S.SID,
    S.SERIAL#,
    P.SPID,
    S.PROGRAM,
    SQ.SQL_FULLTEXT,
    S.LOGON_TIME
FROM
    V$LOCKED_OBJECT L,
    DBA_OBJECTS O,
    V$SESSION S,
    V$PROCESS P,
    V$SQL SQ
WHERE
    L.OBJECT_ID = O.OBJECT_ID
    AND L.SESSION_ID = S.SID
    AND S.PADDR = P.ADDR
    AND S.SQL_ADDRESS = SQ.ADDRESS;

ฆ่าเหมือน

alter system kill session 'SID,SERIAL#';

(ตัวอย่างเช่นalter system kill session '13,36543';)

การอ้างอิงhttp://abeytom.blogspot.com/2012/08/finding-and-fixing-ora-00054-resource.htmlอ้างอิง


5
คำเตือนนี้ควรมีคำตอบพร้อมกับสิทธิพิเศษใดบ้าง ฉันมีCONNECTและแต่ไม่ได้สิ่งที่ต้องการนี้ด้วยบัญชีที่ฉันมีและกล่าวว่าRESOURCE ORA-00942: table or view does not existไม่ใช่ทุกคนที่อ่านหัวข้อนี้จะมีSYSบัญชี
vapcguy

หากคุณเพิ่มคอลัมน์เลือก 'S.OSUSER' เช่นกันคุณจะรู้ว่าผู้ใช้รายใดกำลังทำธุรกรรมนั้นและจะมีประโยชน์ในกรณีที่คุณต้องการตรวจสอบกับผู้ใช้ก่อนที่จะฆ่าเซสชัน
Narasimha

หากเซสชั่นถูกระงับแล้วalter system kill session '13,36543'จะหมดเวลาและเซสชั่นจะไม่ตาย ในกรณีดังกล่าวโปรดดู: stackoverflow.com/a/24306610/587365
Andrew Spencer

ในขณะที่การแทรกข้อมูลลงในตารางโดยใช้connection objectในpythonฉันได้รับข้อผิดพลาดบางอย่าง จากนั้นจะปิดโดยไม่ต้องปิดpython script connection objectตอนนี้ฉันได้รับข้อผิดพลาด "LOCKWAIT" เมื่อฉันพยายามวางตารางในเซสชันอื่น เมื่อฉันลองkill sessionฉันไม่มีสิทธิ์เพียงพอ มีอะไรอีกบ้างที่สามารถกำจัดสิ่งนี้ได้?
sjd

17

มีวิธีแก้ไขปัญหานี้ได้ง่ายมาก

หากคุณเรียกใช้การติดตาม 10046 ในเซสชันของคุณ (google นี้ ... มากเกินไปที่จะอธิบาย) คุณจะเห็นว่าก่อนการดำเนินการ DDL ใด ๆ Oracle จะทำสิ่งต่อไปนี้:

LOCK TABLE 'TABLE_NAME' ไม่ต้องรอ

ดังนั้นหากเซสชันอื่นมีธุรกรรมเปิดคุณจะได้รับข้อผิดพลาด ดังนั้นการแก้ไขคือ ... กลองกลิ้งโปรด ออกการล็อคของคุณเองก่อน DDL และออกจาก 'ไม่รอ'

หมายเหตุพิเศษ:

ถ้าคุณกำลังแยกพาร์ติชั่น oracle พาร์ติชั่นออกมาเพียงแค่ล็อคพาร์ติชั่น. - ดังนั้นคุณสามารถล็อคพาร์ติชั่นย่อยได้

ดังนั้น ... ขั้นตอนต่อไปนี้สามารถแก้ไขปัญหาได้

  1. LOCK TABLE 'TABLE NAME'; - คุณจะ 'รอ' (นักพัฒนาเรียกแฮงค์นี้) จนกว่าจะถึงเซสชันที่มีธุรกรรมคงค้าง นี่คือคิว ดังนั้นอาจมีหลายเซสชันก่อนหน้าคุณ แต่คุณจะไม่ผิดพลาด
  2. ดำเนินการ DDL DDL ของคุณจะเรียกใช้การล็อกโดยไม่ต้องรอ อย่างไรก็ตามเซสชันของคุณได้ล็อคแล้ว ดังนั้นคุณดี
  3. กระทำอัตโนมัติ DDL ซึ่งจะเป็นการปลดล็อค

คำสั่ง DML จะ 'รอ' หรือเป็นนักพัฒนาเรียกมันว่า 'แฮงค์' ในขณะที่ตารางถูกล็อค

ฉันใช้สิ่งนี้ในรหัสที่เรียกใช้จากงานเพื่อวางพาร์ติชัน มันใช้งานได้ดี มันอยู่ในฐานข้อมูลที่แทรกอย่างต่อเนื่องในอัตราหลายร้อยแทรก / วินาที ไม่มีข้อผิดพลาด

หากคุณสงสัย ทำสิ่งนี้ใน 11g ฉันได้ทำสิ่งนี้ใน 10g ก่อนหน้านี้เช่นกันในอดีต


3
ตกลงนี่เป็นสิ่งที่ผิด ใน 11g ใช้ set_ddl_timeout ซึ่งใช้ได้เฉพาะใน 11g oracle ทำคอมมิชชันก่อนที่จะทำ DDL ดังนั้นมันจึงปลดล็อค ใน 11g คุณสามารถรอ DDL ของคุณได้ ตอนนี้ฉันกำลังทำอยู่ ทำงานได้ดี
บ๊อบ

3
ใน 11g คุณควรใช้ LOCK Table table_name ในโหมดเอกสิทธิ์
Kamil Roman

1
สิ่งนี้มีประโยชน์จริง ๆ ถ้าคุณได้รับ ORA-00054 จากงานแบ็ตช์ แต่ฉันสงสัยว่าคนส่วนใหญ่ลงจอดที่นี่ (รวมถึง OP และฉันด้วย) กำลังพัฒนาบางอย่างและได้เปิดเซสชั่นไว้บนโต๊ะเดียวกัน กำลังพยายามวางและสร้างใหม่อีกครั้ง KILL SESSIONเป็นคำตอบที่เหมาะสมสำหรับคนเหล่านี้
Andrew Spencer

@Bob โค้ดตัวอย่างสำหรับทั้ง 11g และแบบเก่าน่าจะดี ไวยากรณ์คืออะไรset_ddl_timeoutและควรเป็นอย่างไร
vapcguy

1
@vapcguy สิ่งนี้ใช้ได้กับฉันใน 11g: ALTER SYSTEM SET ddl_lock_timeout=20;ดูเอกสาร
rshdev

13

ข้อผิดพลาดนี้เกิดขึ้นเมื่อทรัพยากรไม่ว่าง ตรวจสอบว่าคุณมีข้อ จำกัด ในการอ้างอิงใด ๆ ในแบบสอบถาม หรือแม้แต่ตารางที่คุณพูดถึงในแบบสอบถามอาจไม่ว่าง พวกเขาอาจมีส่วนร่วมกับงานอื่น ๆ ซึ่งจะแสดงรายการอย่างแน่นอนในผลลัพธ์ของแบบสอบถามต่อไปนี้:

SELECT * FROM V$SESSION WHERE STATUS = 'ACTIVE'

ค้นหา SID

SELECT * FROM V$OPEN_CURSOR WHERE SID = --the id

1
ไม่ใช่ทุกคนที่จะสามารถเข้าถึงมุมมองเหล่านี้ ORA-00942: table or view does not existฉันได้รับ
vapcguy

ในกรณีเช่นนี้ DB Admins มีหน้าที่รับผิดชอบในการให้ข้อมูลเหล่านั้น
Arunchunaivendan

ไม่เสมอ. ฉันต้องพยายามที่จะให้รหัสนี้เข้าใจและแก้ไขและฉันและบัญชีบริการของฉันจะไม่มีสิทธิ์เหล่านี้
vapcguy

7

สิ่งนี้เกิดขึ้นเมื่อเซสชั่นอื่นนอกเหนือจากที่ใช้ในการเปลี่ยนตารางกำลังถือล็อคน่าจะเป็นเพราะ DML (update / delete / insert) หากคุณกำลังพัฒนาระบบใหม่เป็นไปได้ว่าคุณหรือใครบางคนในทีมของคุณออกคำสั่งการปรับปรุงและคุณสามารถฆ่าเซสชันโดยไม่ส่งผลกระทบมากนัก หรือคุณสามารถคอมมิชชันจากเซสชันนั้นเมื่อคุณรู้ว่าใครเปิดเซสชัน

หากคุณมีสิทธิ์เข้าถึงระบบผู้ดูแลระบบ SQL ให้ใช้เพื่อค้นหาเซสชันที่กระทำผิด และอาจจะฆ่ามัน

คุณสามารถใช้ v $ session และ v $ lock และอื่น ๆ ได้ แต่ฉันขอแนะนำให้คุณ google วิธีค้นหาเซสชันนั้นและวิธีฆ่ามัน

ในระบบการผลิตมันขึ้นอยู่กับ สำหรับ oracle 10g และเก่ากว่าคุณสามารถดำเนินการได้

LOCK TABLE mytable in exclusive mode;
alter table mytable modify mycolumn varchar2(5);

ในเซสชั่นแยกต่างหาก แต่มีสิ่งต่อไปนี้พร้อมในกรณีที่ใช้เวลานานเกินไป

alter system kill session '....

มันขึ้นอยู่กับว่าคุณมีระบบอะไรระบบที่มีอายุมากกว่ามีแนวโน้มที่จะไม่ส่งข้อมูลทุกครั้ง นั่นเป็นปัญหาเนื่องจากอาจมีการล็อคที่ยาวนาน ดังนั้นล็อคของคุณจะป้องกันการล็อคใหม่และรอการล็อคที่รู้ว่าเมื่อไหร่จะได้รับการปล่อยตัว นั่นคือเหตุผลที่คุณมีคำสั่งอื่น ๆ พร้อม หรือคุณอาจมองหาสคริปต์ PLSQL ที่ทำสิ่งเดียวกันโดยอัตโนมัติ

ในเวอร์ชั่น 11g มีตัวแปรสภาพแวดล้อมใหม่ที่กำหนดเวลารอ ฉันคิดว่ามันน่าจะทำสิ่งที่คล้ายกับที่ฉันอธิบาย โปรดทราบว่าปัญหาการล็อคจะไม่หายไป

ALTER SYSTEM SET ddl_lock_timeout=20;
alter table mytable modify mycolumn varchar2(5);

ในที่สุดอาจเป็นการดีที่สุดที่จะรอจนกว่าจะมีผู้ใช้ไม่กี่คนในระบบทำการบำรุงรักษาประเภทนี้


และคุณจะค้นหาเซสชันที่จะฆ่าได้alter system kill session '....อย่างไรหากคุณไม่มีสิทธิ์เข้าถึงมุมมองการจัดการ
vapcguy

ที่ฉันไม่รู้
Arturo Hernandez

7

ในกรณีของฉันฉันค่อนข้างแน่ใจว่าเป็นหนึ่งในเซสชันของฉันเองซึ่งกำลังบล็อก ดังนั้นจึงปลอดภัยที่จะทำสิ่งต่อไปนี้:

  • ฉันพบเซสชันที่ละเมิดด้วย:

    SELECT * FROM V$SESSION WHERE OSUSER='my_local_username';

    เซสชันไม่ได้ใช้งานแต่ยังคงล็อคอยู่ โปรดทราบว่าคุณอาจจำเป็นต้องใช้เงื่อนไขWHEREอื่น ๆในกรณีของคุณ (เช่นลองUSERNAMEหรือMACHINEฟิลด์)

  • ฆ่าเซสชันโดยใช้IDและSERIAL#ได้รับด้านบน:

    alter system kill session '<id>, <serial#>';

แก้ไขโดย @thermz:หากไม่มีการสืบค้นเซสชันเปิดก่อนหน้านี้ให้ลองทำดู แบบสอบถามนี้สามารถช่วยคุณหลีกเลี่ยงข้อผิดพลาดทางไวยากรณ์ขณะที่กำลังฆ่าเซสชัน:

  • SELECT 'ALTER SYSTEM KILL SESSION '''||SID||','||SERIAL#||''' immediate;' FROM V$SESSION WHERE OSUSER='my_local_username_on_OS'

ถ้าไม่มีคิวรีแบบเปิดเซสชันก่อนหน้านี้ให้ลองใช้อันนี้
ร้อน

5

เพียงตรวจสอบกระบวนการที่ถือเซสชั่นและฆ่ามัน มันกลับมาเป็นปกติ

ด้านล่าง SQL จะค้นหากระบวนการของคุณ

SELECT s.inst_id,
   s.sid,
   s.serial#,
   p.spid,
   s.username,
   s.program FROM   gv$session s
   JOIN gv$process p ON p.addr = s.paddr AND p.inst_id = s.inst_id;

จากนั้นฆ่ามัน

ALTER SYSTEM KILL SESSION 'sid,serial#'

หรือ

ตัวอย่างบางส่วนที่ฉันพบทางออนไลน์ดูเหมือนว่าจะต้องใช้รหัสอินสแตนซ์และเปลี่ยนระบบการฆ่าเซสชัน '130,620, @ 1';




3

ฉันจัดการกับข้อผิดพลาดนี้เมื่อสร้างตาราง! เห็นได้ชัดว่าไม่มีปัญหาการโต้แย้งในตารางที่ยังไม่มีอยู่ CREATE TABLEคำสั่งบรรจุCONSTRAINT fk_name FOREIGN KEYข้ออ้างอิงตารางดีที่มีประชากรหนาแน่น ฉันต้อง:

  • ลบคำสั่ง FOREIGN KEY ออกจากคำสั่ง CREATE TABLE
  • สร้างดัชนีในคอลัมน์ FK
  • สร้าง FK

ฉันมีปัญหาเดียวกัน ฉันสามารถสร้างตารางหลังจากที่ฉันลบคำจำกัดความของ fk ออกจากคำสั่ง ddl แต่ฉันไม่สามารถเพิ่มได้แม้หลังจากที่ฉันสร้างดัชนีในคอลัมน์
vadipp

ฉันสามารถแก้ไขได้ ครั้งแรกผมเพิ่มข้อไปnovalidate alter table add constraintวิธีนี้จะช่วยให้มันทำงาน แต่มันล็อค จากนั้นฉันดูที่การล็อคเซสชันเพื่อค้นหาว่าการล็อคเซสชันใด จากนั้นฉันก็ฆ่าเซสชั่นนั้น
vadipp

3

ฉันพบข้อผิดพลาดนี้เมื่อฉันมี 2 สคริปต์ที่ฉันใช้อยู่ ฉันมี:

  • เซสชัน SQL * Plus เชื่อมต่อโดยตรงโดยใช้บัญชีผู้ใช้สคีมา (บัญชี # 1)
  • เซสชัน SQL * Plus อื่นเชื่อมต่อโดยใช้บัญชีผู้ใช้สคีมาอื่น (บัญชี # 2) แต่เชื่อมต่อข้ามลิงก์ฐานข้อมูลเป็นบัญชีแรก

ฉันวิ่งโต๊ะจากนั้นสร้างโต๊ะเป็นบัญชี # 1 ฉันทำการอัปเดตตารางในเซสชันของบัญชี # 2 ไม่ยอมรับการเปลี่ยนแปลง เรียกใช้สคริปต์วาง / สร้างตารางซ้ำอีกครั้งในบัญชี # 1 มีข้อผิดพลาดในdrop table xคำสั่ง

ฉันแก้ไขได้ด้วยการทำงานCOMMIT;ในเซสชัน SQL * Plus ของบัญชี # 2


หากคุณไม่มีสิทธิ์ในการดร็อปโต๊ะคุณจะทำอะไร? คำตอบที่ไม่ถูกต้อง
Shakeer Hussain

1
Shakeer ว่าเป็นเพียงตัวอย่างของสิ่งที่ผมทำเมื่อมันเกิดขึ้นกับฉัน - ไม่ได้วิธีการแก้ปัญหา - ที่อยู่ในบรรทัดสุดท้ายของฉันมาก - COMMIT;ทำงาน หากคุณไม่สามารถวางโต๊ะคุณไม่ได้รับอนุญาตให้แก้ไขสิ่งใดก็ตามที่จะนำคุณเข้าสู่ปัญหานี้ตั้งแต่แรก
vapcguy

-2

ฉันยังเผชิญกับปัญหาที่คล้ายกัน โปรแกรมเมอร์ไม่ต้องทำเพื่อแก้ไขข้อผิดพลาดนี้ ฉันแจ้งทีมงาน DBA ของ Oracle พวกเขาฆ่าเซสชั่นและทำงานเหมือนมีเสน่ห์


1
บางคนยังต้องทำอะไรซักอย่าง จะเป็นอย่างไรถ้าทีม DBA ไม่รู้จะทำอย่างไรและจะฆ่าเซสชันได้อย่างไร คำตอบที่ไม่ดี
vapcguy

1
ถ้า DBA ไม่รู้วิธีฆ่าเซสชันดังนั้นเขาไม่เหมาะที่จะทำงาน
Shakeer Hussain

ทุกคนต้องการทบทวนไวยากรณ์เป็นครั้งคราวเพื่อหลีกเลี่ยงการทำผิด
vapcguy

-5

ทางออกที่ได้จากลิงค์ของ Shashi นั้นดีที่สุด ... ไม่จำเป็นต้องติดต่อ dba หรือคนอื่น

ทำการสำรองข้อมูล

create table xxxx_backup as select * from xxxx;

ลบแถวทั้งหมด

delete from xxxx;
commit;

ใส่สำรองของคุณ

insert into xxxx (select * from xxxx_backup);
commit;

10
ลบ / ตัดไม่สามารถใช้แทนกันได้ ประสิทธิภาพการลบจำนวนมากมีผลกระทบอย่างมาก นี่มันแย่จริงๆ
บ๊อบ

ฉันคิดว่านี่เป็นรูปแบบทั่วไป
Shawn Xue
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.