SQL Server selalu menggunakan kombinasi Split, Sort, dan Collapse operator ketika mempertahankan indeks unik sebagai bagian dari pembaruan yang mempengaruhi (atau mungkin mempengaruhi) lebih dari satu baris.
Bekerja melalui contoh dalam pertanyaan, kita bisa menulis pembaruan sebagai pembaruan satu baris terpisah untuk masing-masing dari empat baris yang ada:
-- Per row updates
UPDATE dbo.Banana SET pk = 2 WHERE pk = 1;
UPDATE dbo.Banana SET pk = 3 WHERE pk = 2;
UPDATE dbo.Banana SET pk = 4 WHERE pk = 3;
UPDATE dbo.Banana SET pk = 5 WHERE pk = 4;
Masalahnya adalah bahwa pernyataan pertama akan gagal, karena berubah pk
dari 1 menjadi 2, dan sudah ada baris di mana pk
= 2. Mesin penyimpanan SQL Server mengharuskan indeks unik tetap unik di setiap tahap pemrosesan, bahkan dalam satu pernyataan tunggal . Ini adalah masalah yang diselesaikan oleh Split, Sort, dan Collapse.
Membagi
Langkah pertama adalah Membagi setiap pernyataan pembaruan menjadi penghapusan diikuti oleh sisipan:
DELETE dbo.Banana WHERE pk = 1;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Operator Split menambahkan kolom kode tindakan ke aliran (di sini diberi label Act1007):
Kode tindakan adalah 1 untuk pembaruan, 3 untuk penghapusan, dan 4 untuk sisipan.
Menyortir
Pernyataan terbagi di atas masih akan menghasilkan pelanggaran kunci unik sementara sementara, jadi langkah selanjutnya adalah mengurutkan pernyataan dengan kunci indeks unik yang diperbarui ( pk
dalam kasus ini), lalu dengan kode tindakan. Untuk contoh ini, ini berarti bahwa penghapusan (3) pada kunci yang sama dipesan sebelum dimasukkan (4). Pesanan yang dihasilkan adalah:
-- Sort (pk, action)
DELETE dbo.Banana WHERE pk = 1;
DELETE dbo.Banana WHERE pk = 2;
INSERT dbo.Banana (pk, c1, c2) VALUES (2, 'A', 'W');
DELETE dbo.Banana WHERE pk = 3;
INSERT dbo.Banana (pk, c1, c2) VALUES (3, 'B', 'X');
DELETE dbo.Banana WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (4, 'C', 'Y');
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Jatuh
Tahap sebelumnya sudah cukup untuk menjamin terhindar dari pelanggaran keunikan palsu dalam semua kasus. Sebagai pengoptimalan, Collapse menggabungkan penghapusan dan sisipan yang berdekatan pada nilai kunci yang sama ke dalam pembaruan:
-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1;
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2;
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3;
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4;
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z');
Pasangan hapus / sisipkan untuk pk
nilai 2, 3, dan 4 telah digabungkan ke dalam pembaruan, meninggalkan satu penghapusan tunggal pada pk
= 1, dan sebuah sisipan untuk pk
= 5.
Perkecil grup operator baris menurut kolom kunci, dan perbarui kode tindakan untuk mencerminkan hasil kehancuran:
Pembaruan Indeks Clustered
Operator ini dilabeli sebagai Pembaruan, tetapi mampu menyisipkan, memperbarui, dan menghapus. Tindakan mana yang diambil oleh Pembaruan Indeks Clustered per baris ditentukan oleh nilai kode tindakan di baris itu. Operator memiliki properti Tindakan untuk mencerminkan mode operasi ini:
Penghitung modifikasi baris
Perhatikan bahwa ketiga pembaruan di atas tidak mengubah kunci indeks unik yang dipertahankan. Akibatnya, kami telah mengubah pembaruan ke kolom kunci dalam indeks menjadi pembaruan dari kolom non-kunci ( c1
dan c2
), ditambah dengan penghapusan dan sisipan. Baik penghapusan maupun penyisipan dapat menyebabkan pelanggaran kunci unik yang salah.
Sisipan atau penghapusan memengaruhi setiap kolom di baris, sehingga statistik yang terkait dengan setiap kolom akan menambah penghitung modifikasinya. Untuk pembaruan, hanya statistik dengan salah satu kolom yang diperbarui sebagai kolom utama yang penghitung modifikasinya bertambah (bahkan jika nilainya tidak berubah).
Penghitung modifikasi baris statistik karenanya menunjukkan 2 perubahan ke pk
, dan 5 untuk c1
dan c2
:
-- Collapse (pk)
DELETE dbo.Banana WHERE pk = 1; -- All columns modified
UPDATE dbo.Banana SET c1 = 'A', c2 = 'W' WHERE pk = 2; -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'B', c2 = 'X' WHERE pk = 3; -- c1 and c2 modified
UPDATE dbo.Banana SET c1 = 'C', c2 = 'Y' WHERE pk = 4; -- c1 and c2 modified
INSERT dbo.Banana (pk, c1, c2) VALUES (5, 'D', 'Z'); -- All columns modified
Catatan: Hanya perubahan yang diterapkan pada objek dasar (heap atau clustered index) yang memengaruhi penghitung modifikasi baris statistik. Non-clustered indexes adalah struktur sekunder, yang mencerminkan perubahan yang telah dibuat pada objek dasar. Mereka tidak mempengaruhi penghitung modifikasi baris statistik sama sekali.
Jika suatu objek memiliki beberapa indeks unik, kombinasi Split, Sortir, Perkecil digunakan untuk mengatur pembaruan masing-masing. SQL Server mengoptimalkan kasus ini untuk indeks nonclustered dengan menyimpan hasil Split ke Spool Eager Table, kemudian memutar ulang yang ditetapkan untuk setiap indeks unik (yang akan memiliki Urutkan sendiri berdasarkan kunci indeks + kode tindakan, dan Perkecil).
Efek pada pembaruan statistik
Pembaruan statistik otomatis (jika diaktifkan) terjadi ketika pengoptimal permintaan membutuhkan informasi statistik dan pemberitahuan bahwa statistik yang ada sudah ketinggalan zaman (atau tidak valid karena perubahan skema). Statistik dianggap ketinggalan zaman ketika jumlah modifikasi yang dicatat melebihi ambang batas.
Pengaturan Split / Sort / Collapse menghasilkan modifikasi baris yang berbeda dicatat daripada yang diharapkan. Ini, pada gilirannya, berarti bahwa pembaruan statistik dapat dipicu cepat atau lambat daripada yang terjadi sebaliknya.
Pada contoh di atas, modifikasi baris untuk kolom kunci bertambah 2 (perubahan bersih) daripada 4 (satu untuk setiap baris tabel yang terpengaruh), atau 5 (satu untuk setiap penghapusan / perbarui / masukkan yang dihasilkan oleh Perkecil).
Selain itu, kolom non-kunci yang secara logis tidak diubah oleh kueri asli mengakumulasi modifikasi baris, yang dapat berjumlah sebanyak dua kali lipat baris tabel yang diperbarui (satu untuk setiap penghapusan, dan satu untuk setiap sisipan).
Jumlah perubahan yang direkam tergantung pada tingkat tumpang tindih antara nilai kolom kunci lama dan baru (dan sejauh mana penghapusan dan sisipan terpisah dapat diciutkan). Menyetel ulang tabel di antara setiap eksekusi, kueri berikut menunjukkan efek pada penghitung modifikasi baris dengan tumpang tindih yang berbeda:
UPDATE dbo.Banana SET pk = pk + 0; -- Full overlap
UPDATE dbo.Banana SET pk = pk + 1;
UPDATE dbo.Banana SET pk = pk + 2;
UPDATE dbo.Banana SET pk = pk + 3;
UPDATE dbo.Banana SET pk = pk + 4; -- No overlap