ORA-00054: sumber daya sibuk dan memperoleh dengan NOWAIT ditentukan atau batas waktu habis


193

Mengapa saya mendapatkan kesalahan basis data ini ketika saya memperbarui tabel?

GALAT di baris 1: ORA-00054: sumber daya sibuk dan memperoleh dengan NOWAIT ditentukan atau batas waktu habis


22
Biasanya membantu jika Anda memposting pernyataan yang mengarah ke kesalahan
Gary Myers

Jawaban:


222

Meja Anda sudah dikunci oleh beberapa permintaan. Sebagai contoh, Anda mungkin telah mengeksekusi "select for update" dan belum melakukan / rollback dan memecat kueri pemilihan lain. Lakukan komit / rollback sebelum menjalankan kueri Anda.


47
Saya akan menambahkan 'di sesi lain' untuk itu. Satu skenario umum adalah bahwa Anda telah menguji pembaruan di alat, katakan SQL Developer atau Toad, dan kemudian telah mencoba untuk menjalankannya di tempat lain sementara sesi pertama masih memegang kunci. Jadi, Anda perlu komit / kembalikan sesi lain sebelum Anda dapat menjalankan pembaruan lagi.
Alex Poole

1
Kemungkinan besar DML (masukkan / hapus / perbarui) daripada kueri. Dan di sesi lain. Hanya karena pria yang bertanya itu sepertinya seorang pemula, jawabannya mungkin benar. Tetapi Anda TIDAK BISA berkomitmen atas nama pengguna lain dalam sistem produksi.
Arturo Hernandez

4
Nah, apa yang membuat saya mengalami masalah itu adalah di Toad: Seorang kolega berada di meja yang sama dengan saya ketika saya ingin menghapus satu baris, dan jadi saya tidak bisa menghapusnya. Ketika dia pindah ke meja lain saya bisa menghapus baris. Mungkin membantu seseorang di luar sana. Tapi ini hanya jika Anda bekerja dengan Toad di dalam tabel, dan bukan untuk querys.
DatRid

baru-baru ini terjadi di server pementasan kami (aplikasi Spring di WebSphere). Solusi adalah untuk memisahkan skrip pembaruan basis data "monolitik" menjadi potongan-potongan kecil dengan memindahkan pernyataan penyebab kesalahan ke dalam layanan pembaruan terpisah yang menggunakan transaksi terpisah: @Transaksional (propagasi = Propagasi.REQUIRES_NEW)
actc

103

dari sini ORA-00054: sumber daya sibuk dan dapatkan dengan NOWAIT yang ditentukan

Anda juga dapat mencari sql, nama pengguna, mesin, informasi port dan sampai ke proses aktual yang memegang koneksi

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
Saya harus menghapus s.port dari kueri tapi itu biar saya menemukan pelakunya
Sibster

kunci sementara. jadi jika sisipan datang, maka Anda langsung berkomitmen. itu tidak akan muncul dalam permintaan ini. Anda masih bisa mendapatkan kesalahan jika Anda mengeluarkan 'DDL'. saat transaksi terbuka. lihat posting saya di bawah ini. Ini sangat mudah untuk dikerjakan.
Bob

4
Saya mengalami masalah yang sama dengan OP, tetapi saya tidak dapat melihat tabel mana pun yang Anda sebutkan (pilih * dari V $ LOCKED_OBJECT, misalnya, mengembalikan ORA-00942: tabel atau tampilan tidak ada). Ada ide?
random_forest_fanatic

3
Anda mungkin tidak memiliki hak istimewa yang memadai untuk melihat pandangan manajemen.
njplumridge

Menindaklanjuti S.Portmasalah: 11.2 dokumen disebutkan Portsebagai bidang dalam V$Session, tetapi bagi saya, menggunakan 11.1, S.Porttidak valid. Apakah ditambahkan untuk 11.2, mungkin?

64

Tolong Bunuh Sesi Oracle

Gunakan kueri di bawah ini untuk memeriksa info sesi aktif

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;

bunuh seperti

alter system kill session 'SID,SERIAL#';

(Misalnya alter system kill session '13,36543',;)

Referensi http://abeytom.blogspot.com/2012/08/finding-and-fixing-ora-00054-resource.html


5
Haruskah keberatan jawaban ini dengan hak istimewa apa yang diperlukan. Saya punya CONNECTdan RESOURCE, tapi tidak apa pun yang dibutuhkan, dengan akun yang saya miliki, dan katakan ORA-00942: table or view does not exist. Tidak semua orang yang membaca utas ini akan memiliki SYSakun.
vapcguy

Jika Anda menambahkan kolom pilih 'S.OSUSER' juga Anda akan tahu pengguna mana yang menjalankan transaksi itu dan itu akan berguna jika Anda ingin memeriksa dengan pengguna sebelum membunuh sesi.
Narasimha

Jika sesi digantung, maka alter system kill session '13,36543'akan habis dan sesi tidak akan mati. Dalam hal ini, lihat: stackoverflow.com/a/24306610/587365
Andrew Spencer

Saat memasukkan data ke tabel menggunakan connection objectdi pythonsaya mendapat beberapa kesalahan. Kemudian python scriptditutup tanpa menutup dengan benar connection object. Sekarang saya mendapatkan kesalahan "LOCKWAIT" ketika saya mencoba untuk menjatuhkan tabel di sesi lain. Ketika saya coba kill sessionsaya tidak memiliki cukup privilage. Apa lagi yang bisa dilakukan untuk menyingkirkan ini?
sjd

17

Ada cara yang sangat mudah untuk mengatasi masalah ini.

Jika Anda menjalankan jejak 10046 di sesi Anda (google this ... terlalu banyak menjelaskan). Anda akan melihat bahwa sebelum operasi DDL, Oracle melakukan hal berikut:

LOCK TABLE 'TABLE_NAME' TANPA TUNGGU

Jadi, jika sesi lain memiliki transaksi terbuka Anda mendapatkan kesalahan. Jadi, perbaiki adalah ... drum roll tolong. Keluarkan kunci Anda sendiri sebelum DDL dan tinggalkan 'NO WAIT'.

Catatan Khusus:

jika Anda melakukan pemecahan / menjatuhkan partisi oracle hanya mengunci partisi. - jadi kamu hanya bisa mengunci sub partisi partisi.

Jadi ... Langkah-langkah berikut memperbaiki masalah.

  1. LOCK TABLE 'NAMA TABLE'; - Anda akan 'menunggu' (pengembang menyebut ini menggantung). sampai sesi dengan transaksi terbuka, komit. Ini adalah antrian. jadi mungkin ada beberapa sesi di depan Anda. tetapi Anda TIDAK akan kesalahan.
  2. Jalankan DDL. DDL Anda kemudian akan menjalankan kunci dengan TIDAK SABAR. Namun, sesi Anda telah memperoleh kunci. Jadi kamu baik-baik saja.
  3. Komitmen otomatis DDL. Ini membebaskan kunci.

Pernyataan DML akan 'menunggu' atau sebagai pengembang menyebutnya 'hang' saat tabel dikunci.

Saya menggunakan ini dalam kode yang dijalankan dari pekerjaan untuk menjatuhkan partisi. Ini bekerja dengan baik. Itu dalam database yang terus-menerus memasukkan pada tingkat beberapa ratus sisipan / detik. Tidak ada kesalahan

jika Anda bertanya-tanya. Melakukan ini dalam 11g. Saya telah melakukan ini dalam 10g sebelumnya juga di masa lalu.


3
ok, ini salah. dalam 11g, gunakan set_ddl_timeout, Ini hanya tersedia dalam 11g. oracle melakukan komit sebelum melakukan DDL, sehingga melepaskan kunci. Dalam 11g, Anda dapat meminta DDL menunggu. Saya melakukan itu sekarang. Bekerja dengan baik.
Bob

3
dalam 11g Anda harus menggunakan LOCK TABLE table_name DALAM MODE EKSKLUSIF;
Kamil Roman

1
Ini benar-benar berguna jika Anda mendapatkan ORA-00054 dari pekerjaan batch, tapi saya curiga sebagian besar orang mendarat di sini (termasuk OP, dan saya) sedang melakukan beberapa pengembangan dan telah meninggalkan sesi terbuka melakukan sisipan di meja yang sama dengan mereka. sedang mencoba untuk menjatuhkan dan menciptakan kembali. KILL SESSIONadalah jawaban yang tepat untuk orang-orang ini.
Andrew Spencer

@ Bob contoh kode untuk 11g dan cara lama akan lebih baik. Untuk apa sintaksinya set_ddl_timeoutdan untuk apa itu?
vapcguy

1
@vapcguy ini bekerja untuk saya di 11g: ALTER SYSTEM SET ddl_lock_timeout=20;lihat dokumen
rshdev

13

Kesalahan ini terjadi saat sumber daya sibuk. Periksa apakah Anda memiliki kendala referensial dalam kueri. Atau bahkan tabel yang telah Anda sebutkan dalam kueri mungkin sibuk. Mereka mungkin terlibat dengan beberapa pekerjaan lain yang pasti akan tercantum dalam hasil permintaan berikut:

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

Temukan SID,

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

1
Tidak semua orang akan memiliki akses ke tampilan ini. Saya mengerti ORA-00942: table or view does not exist.
vapcguy

Dalam kasus seperti itu, Admin DB bertanggung jawab untuk menyediakan informasi tersebut.
Arunchunaivendan

Tidak selalu. Saya harus mencoba mendapatkan kode untuk memecahkan masalah ini dan mengatasinya, dan baik saya maupun akun layanan saya tidak akan memiliki hak-hak ini.
vapcguy

7

Ini terjadi ketika sesi selain yang digunakan untuk mengubah tabel menahan kemungkinan karena DML (perbarui / hapus / sisipkan). Jika Anda mengembangkan sistem baru, kemungkinan Anda atau seseorang di tim Anda mengeluarkan pernyataan pembaruan dan Anda dapat mematikan sesi tanpa banyak konsekuensi. Atau Anda dapat melakukan dari sesi itu setelah Anda tahu siapa yang memiliki sesi terbuka.

Jika Anda memiliki akses ke sistem admin SQL, gunakan untuk menemukan sesi yang menyinggung. Dan mungkin membunuhnya.

Anda dapat menggunakan v $ session dan v $ lock dan lainnya tetapi saya sarankan Anda google cara menemukan sesi itu dan kemudian cara membunuhnya.

Dalam sistem produksi, itu sangat tergantung. Untuk oracle 10g dan lebih tua, Anda bisa mengeksekusi

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

Dalam sesi terpisah tetapi siapkan yang berikut jika perlu waktu terlalu lama.

alter system kill session '....

Tergantung pada sistem apa yang Anda miliki, sistem yang lebih lama lebih cenderung untuk tidak melakukan setiap waktu. Itu masalah karena mungkin ada kunci yang berdiri lama. Jadi kunci Anda akan mencegah kunci baru dan menunggu kunci yang tahu kapan akan dirilis. Itu sebabnya Anda memiliki pernyataan lain yang siap. Atau Anda bisa mencari skrip PLSQL di luar sana yang melakukan hal serupa secara otomatis.

Dalam versi 11g ada variabel lingkungan baru yang menetapkan waktu tunggu. Saya pikir itu mungkin melakukan sesuatu yang mirip dengan yang saya jelaskan. Pikiran Anda bahwa masalah penguncian tidak hilang.

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

Akhirnya mungkin yang terbaik adalah menunggu sampai ada beberapa pengguna dalam sistem untuk melakukan pemeliharaan semacam ini.


Dan bagaimana Anda mengetahui sesi untuk membunuh alter system kill session '....jika Anda tidak memiliki akses ke pandangan manajemen?
vapcguy

Itu saya tidak tahu.
Arturo Hernandez

7

Dalam kasus saya, saya cukup yakin itu adalah salah satu sesi saya sendiri yang menghalangi. Karena itu, aman untuk melakukan hal berikut:

  • Saya menemukan sesi menyinggung dengan:

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

    Sesi ini tidak aktif , tetapi entah bagaimana masih memegang kunci. Perhatikan, bahwa Anda mungkin perlu menggunakan beberapa kondisi WHERE lain dalam kasus Anda (mis. Coba USERNAMEatau MACHINEbidang).

  • Membunuh sesi menggunakan IDdan SERIAL#diperoleh di atas:

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

Diedit oleh @thermz: Jika tidak ada pertanyaan sesi terbuka sebelumnya yang berfungsi, coba yang ini. Kueri ini dapat membantu Anda menghindari kesalahan sintaksis saat mengakhiri sesi:

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

Jika tidak ada kueri sesi terbuka sebelumnya yang berfungsi, coba yang ini.
thermz

5

Cukup periksa proses memegang sesi dan Bunuh itu. Kembali normal.

Di bawah ini SQL akan menemukan proses Anda

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;

Kalau begitu bunuh saja

ALTER SYSTEM KILL SESSION 'sid,serial#'

ATAU

beberapa contoh yang saya temukan online tampaknya memerlukan instance id dan juga mengubah sesi sistem kill '130.620, @ 1';



4

select
   c.owner,
   c.object_name,
   c.object_type,
   b.sid,
   b.serial#,
   b.status,
   b.osuser,
   b.machine
from
   v$locked_object a,
   v$session b,
   dba_objects c
where
   b.sid = a.session_id
and
   a.object_id = c.object_id;
   
   ALTER SYSTEM KILL SESSION 'sid,serial#';


3

Saya berhasil mengenai kesalahan ini ketika hanya membuat tabel! Jelas tidak ada masalah pertengkaran di atas meja yang belum ada. The CREATE TABLEpernyataan berisi CONSTRAINT fk_name FOREIGN KEYklausul referensi meja yang penduduknya. Saya harus:

  • Hapus klausa KUNCI ASING dari pernyataan CREATE TABLE
  • Buat INDEX di kolom FK
  • Buat FK

Saya hanya punya masalah yang sama. Saya dapat membuat tabel setelah saya menghapus definisi fk dari pernyataan ddl, tetapi saya tidak dapat menambahkannya bahkan setelah saya membuat indeks pada kolom.
vadipp

Saya bisa menyelesaikannya. Pertama, saya menambahkan novalidateklausa ke alter table add constraint. Ini entah bagaimana membiarkannya berjalan, tetapi terkunci. Kemudian saya melihat kunci sesi untuk mengetahui sesi mana yang dikunci. Dan kemudian saya membunuh sesi itu.
vadipp

3

Saya memiliki kesalahan ini terjadi ketika saya memiliki 2 skrip yang saya jalankan. Saya punya:

  • Sesi SQL * Plus terhubung langsung menggunakan akun pengguna skema (akun # 1)
  • Sesi SQL * Plus lain terhubung menggunakan akun pengguna skema yang berbeda (akun # 2), tetapi menghubungkan seluruh tautan basis data sebagai akun pertama

Saya menjalankan setetes tabel, lalu membuat tabel sebagai akun # 1. Saya menjalankan pembaruan tabel pada sesi akun # 2. Tidak melakukan perubahan. Menjalankan ulang skrip drop / pembuatan tabel sebagai akun # 1. Terjadi kesalahan pada drop table xperintah.

Saya menyelesaikannya dengan menjalankan COMMIT;sesi SQL * Plus di akun # 2.


Jika Anda tidak memiliki izin untuk menjatuhkan tabel, lalu apa yang akan Anda lakukan? Jawaban buruk
Shakeer Hussain

1
Shakeer, itu hanya contoh dari apa yang saya lakukan ketika itu terjadi pada saya - bukan solusi untuk masalah - yang ada di baris terakhir saya - menjalankan a COMMIT;. Jika Anda bahkan tidak bisa menjatuhkan meja, Anda tidak memiliki izin untuk mengubah apa pun yang akan membawa Anda ke masalah ini sejak awal.
vapcguy

-2

Saya juga menghadapi Masalah serupa. Tidak ada programmer yang harus dilakukan untuk menyelesaikan kesalahan ini. Saya memberi tahu tim DBA oracle saya. Mereka membunuh sesi dan bekerja seperti pesona.


1
Seseorang masih harus melakukan sesuatu. Bagaimana jika tim DBA tidak tahu apa yang harus dilakukan, dan bagaimana cara membunuh sesi? Jawaban yang buruk
vapcguy

1
Jika DBA tidak tahu cara membunuh sesi maka dia tidak layak bekerja
Shakeer Hussain

Setiap orang membutuhkan penyegaran pada sintaksis dari waktu ke waktu untuk menghindari kesalahan.
vapcguy

-5

Solusi yang diberikan oleh tautan Shashi adalah yang terbaik ... tidak perlu menghubungi dba atau orang lain

buat cadangan

create table xxxx_backup as select * from xxxx;

hapus semua baris

delete from xxxx;
commit;

masukkan cadangan Anda.

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

10
delete / truncate tidak bisa dipertukarkan. melakukan sejumlah besar penghapusan memiliki implikasi kinerja yang sangat besar. Ini sangat buruk.
Bob

Saya pikir ini adalah pola umum.
Shawn Xue
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.