"Tatanan" bersifat deterministik dari sudut pandang Anda hanya jika Anda menyertakan ORDER BY dalam kueri Anda. Apakah itu deterministik dari sudut pandang server adalah detail implementasi, tidak dapat diandalkan.
Untuk penguncian, dua pernyataan DML yang identik dapat memblokir (tetapi tidak menemui jalan buntu) satu sama lain. Misalnya:
CREATE TABLE THE_TABLE (
ID INT PRIMARY KEY
);
Transaksi A:
INSERT INTO THE_TABLE VALUES(1);
Transaksi B:
INSERT INTO THE_TABLE VALUES(1);
Pada titik ini, Transaksi B macet sampai Transaksi A melakukan atau memutar kembali. Jika A melakukan, B gagal karena pelanggaran PRIMARY KEY. Jika A mundur, B berhasil.
Contoh serupa dapat dibuat untuk UPDATE dan DELETE.
Poin pentingnya adalah bahwa pemblokiran tidak akan bergantung pada rencana eksekusi - tidak peduli bagaimana Oracle memilih untuk mengoptimalkan kueri Anda, Anda akan selalu memiliki perilaku pemblokiran yang sama. Anda mungkin ingin membaca tentang Penguncian Otomatis dalam Operasi DML untuk info lebih lanjut.
Adapun mati -locks, mereka dapat dicapai dengan banyak pernyataan. Misalnya:
A: INSERT INTO THE_TABLE VALUES(1);
B: INSERT INTO THE_TABLE VALUES(2);
A: INSERT INTO THE_TABLE VALUES(2);
B: INSERT INTO THE_TABLE VALUES(1); -- SQL Error: ORA-00060: deadlock detected while waiting for resource
Atau, mungkin dengan pernyataan yang mengubah lebih dari satu baris dalam urutan yang berbeda dan beberapa waktu yang sangat tidak menguntungkan (ada yang bisa mengkonfirmasi ini?).
--- UPDATE ---
Menanggapi pembaruan pertanyaan Anda, izinkan saya membuat pengamatan umum:Jika utas eksekusi yang bersamaan mengunci objek dalam urutan yang konsisten , kebuntuan tidak mungkin. Ini berlaku untuk semua jenis penguncian, baik itu mutex dalam program multi-utas rata-rata Anda (misalnya, lihat pemikiran Herb Sutter tentang Hirarki Kunci) atau baik itu basis data. Setelah Anda mengubah urutan sedemikian rupa sehingga setiap dua kunci "terbalik", potensi kebuntuan diperkenalkan.
Tanpa memindai indeks, Anda memperbarui (dan mengunci ) baris dalam satu urutan, dan dengan indeks di urutan lain. Jadi, ini mungkin yang terjadi dalam kasus Anda:
- Jika Anda menonaktifkan pemindaian indeks untuk kedua transaksi bersamaan , keduanya mengunci baris dalam urutan yang sama [X], jadi tidak mungkin terjadi deadlock.
- Jika Anda mengaktifkan pemindaian indeks hanya untuk satu transaksi , mereka tidak lagi mengunci baris dalam urutan yang sama, sehingga berpotensi menemui jalan buntu.
- Jika Anda mengaktifkan pemindaian indeks untuk kedua transaksi , sekali lagi keduanya mengunci baris dalam urutan yang sama, dan kebuntuan tidak mungkin terjadi (lanjutkan dan coba
alter session set optimizer_index_cost_adj = 1;
di kedua sesi dan Anda akan melihat).
[X] Meskipun saya tidak akan bergantung pada pemindaian tabel lengkap yang memiliki pesanan yang dijamin - mungkin saja cara Oracle saat ini dalam keadaan khusus ini bekerja, dan beberapa Oracle di masa depan atau keadaan yang berbeda mungkin menghasilkan perilaku yang berbeda.
Jadi, kehadiran indeks bersifat insidental - masalah sebenarnya adalah pemesanan. Kebetulan pemesanan di UPDATE dapat dipengaruhi oleh indeks, tetapi jika kami dapat memengaruhi pemesanan dengan cara lain, kami akan mendapatkan hasil yang serupa.
Karena UPDATE tidak memiliki ORDER BY, Anda tidak dapat menjamin urutan penguncian hanya dengan UPDATE. Namun, jika Anda memisahkan mengunci dari memperbarui, maka Anda bisa menjamin urutan kunci:
SELECT ... ORDER BY ... FOR UPDATE;
Sementara kode asli Anda menyebabkan kebuntuan di lingkungan Oracle 10 saya, kode berikut tidak:
Sesi 1:
declare
cursor cur is select * from deadlock_test where a > 0 order by a for update;
begin
while true loop
for locked_row in cur loop
update deadlock_test set a = -99999999999999999999 where current of cur;
end loop;
rollback;
end loop;
end;
/
Sesi 2:
alter session set optimizer_index_cost_adj = 1;
declare
cursor cur is select * from deadlock_test where a > 0 order by a for update;
begin
while true loop
for locked_row in cur loop
update deadlock_test set a = -99999999999999999999 where current of cur;
end loop;
rollback;
end loop;
end;
/