Dalam pertanyaan saya sebelumnya, Apakah ide yang baik untuk menonaktifkan eskalasi kunci sambil menambahkan kolom terhitung baru ke tabel? , Saya membuat kolom yang dihitung:
ALTER TABLE dbo.tblBGiftVoucherItem
ADD isUsGift AS CAST
(
ISNULL(
CASE WHEN sintMarketID = 2
AND strType = 'CARD'
AND strTier1 LIKE 'GG%'
THEN 1
ELSE 0
END
, 0)
AS BIT
) PERSISTED;
Kolom yang dihitung adalah PERSISTED
, dan menurut computed_column_definition (Transact-SQL) :
TERTENTU
Menentukan bahwa Mesin Basis Data akan secara fisik menyimpan nilai yang dihitung dalam tabel, dan memperbarui nilai ketika kolom lain yang bergantung pada kolom yang dihitung diperbarui. Menandai kolom yang dihitung sebagai PERSISTED memungkinkan indeks dibuat pada kolom yang dihitung yang bersifat deterministik, tetapi tidak tepat. Untuk informasi lebih lanjut, lihat Indeks pada Kolom yang Dihitung. Setiap kolom yang dihitung yang digunakan sebagai kolom partisi dari tabel yang dipartisi harus secara eksplisit ditandai PERSISTED. computed_column_expression harus deterministik ketika PERSISTED ditentukan.
Tetapi ketika saya mencoba membuat indeks pada kolom saya, saya mendapatkan kesalahan berikut:
CREATE INDEX FIX_tblBGiftVoucherItem_incl
ON dbo.tblBGiftVoucherItem (strItemNo)
INCLUDE (strTier3)
WHERE isUsGift = 1;
Indeks yang difilter 'FIX_tblBGiftVoucherItem_incl' tidak dapat dibuat di tabel 'dbo.tblBGiftVoucherItem' karena kolom 'isUsGift' dalam ekspresi filter adalah kolom yang dihitung. Tulis ulang ekspresi filter sehingga tidak termasuk kolom ini.
Bagaimana saya bisa membuat indeks yang difilter pada kolom yang dihitung?
atau
Apakah ada solusi alternatif?
sumber
WHERE (sintMarketID = 2 AND strType = 'CARD' AND strTier1 LIKE 'GG%')
.Jawaban:
Sayangnya pada SQL Server 2014, tidak ada kemampuan untuk membuat
Filtered Index
tempat Filter berada pada kolom yang dikomputasi (terlepas dari apakah itu tetap ada atau tidak).Sudah ada Item Sambung yang dibuka sejak 2009, jadi silakan lanjutkan dan pilih. Mungkin Microsoft akan memperbaikinya suatu hari.
Aaron Bertrand memiliki artikel yang mencakup sejumlah masalah lain dengan Indeks yang Difilter .
sumber
Meskipun Anda tidak dapat membuat indeks yang difilter pada kolom yang tetap, ada solusi yang cukup sederhana yang mungkin dapat Anda gunakan.
Sebagai ujian, saya telah membuat tabel sederhana dengan
IDENTITY
kolom, dan kolom yang dihitung tetap berdasarkan kolom identitas:Lalu, saya membuat tampilan terikat skema berdasarkan tabel dengan filter pada kolom yang dihitung:
Berikutnya, saya membuat indeks berkerumun pada tampilan terikat skema, yang memiliki efek mempertahankan nilai yang disimpan dalam tampilan, termasuk nilai kolom yang dihitung:
Masukkan beberapa data uji ke dalam tabel:
Buat item statistik dan indeks pada tampilan:
Melakukan
SELECT
pernyataan terhadap tabel dengan kolom tetap sekarang dapat secara otomatis menggunakan tampilan tetap, jika pengoptimal permintaan menentukan masuk akal untuk melakukannya:Rencana eksekusi aktual untuk kueri di atas menunjukkan optimizer kueri memilih untuk menggunakan tampilan bertahan untuk mengembalikan hasil:
Anda mungkin telah memperhatikan konversi eksplisit dalam
WHERE
klausa di atas. Ini eksplisitCONVERT(INT, 26)
memungkinkan pengoptimal permintaan untuk menggunakan objek statistik dengan benar untuk memperkirakan jumlah baris yang akan dikembalikan oleh permintaan. Jika kita menulis kueri denganWHERE pv.TestComputedColumn = 26
, pengoptimal kueri mungkin tidak memperkirakan jumlah baris dengan benar karena 26 dianggap sebagai aTINY INT
; ini dapat menyebabkan SQL Server tidak menggunakan tampilan bertahan. Konversi tersirat bisa sangat menyakitkan, dan membayar untuk secara konsisten menggunakan tipe data yang benar untuk perbandingan dan bergabung.Tentu saja, semua standar "gotcha" yang dihasilkan dari penggunaan skema mengikat berlaku untuk skenario di atas; ini dapat mencegah penggunaan solusi ini di semua skenario. Misalnya, tidak akan lagi mungkin untuk memodifikasi tabel dasar tanpa terlebih dahulu menghapus skema pengikatan dari tampilan. Untuk melakukan itu, Anda harus menghapus indeks berkerumun dari tampilan.
Jika Anda tidak memiliki SQL Server Enterprise Edition, pengoptimal kueri tidak akan secara otomatis menggunakan tampilan bertahan untuk kueri yang tidak secara langsung mereferensikan tampilan menggunakan
WITH (NOEXPAND)
petunjuk. Untuk menyadari manfaat menggunakan tampilan bertahan dalam versi non-Enterprise Edition, Anda harus menulis ulang kueri di atas untuk sesuatu seperti:Terima kasih kepada Ian Ringrose karena telah menunjukkan batasan Edisi Enterprise di atas, dan untuk Paul White atas
(NOEXPAND)
petunjuknya.Jawaban oleh Paul ini memiliki beberapa detail menarik tentang pengoptimal permintaan sehubungan dengan pandangan yang ada.
sumber
TestComputedColumn
sebaliknya. Namun, karena indeks berkerumun berisi semua data untuk tabel / tampilan, saya memutuskan akan lebih baik menggunakan angka yang meningkat secara monoton sebagai kunci pengelompokan. Catatan, saya tidak benar-benar menguji anggapan itu, dan mungkin sebenarnya tidak benar untuk beberapa variasi repro.Dari
Create Index
danwhere
klausulnya, ini tidak mungkin:Sumber: MSDN
sumber
Sebelum kami menghitung kolom, kami menggunakan pemicu untuk menghitung nilai kolom setiap kali baris diubah atau dimasukkan.
(Pemicu juga bisa digunakan untuk menyisipkan / menghapus PK item dari tabel ke-2 yang kemudian digunakan dalam kueri.)
sumber
Ini adalah upaya untuk meningkatkan pekerjaan Max Vernon . Dalam solusinya, ia menyarankan menggunakan 2 indeks pada tampilan dan objek statistik.
Indeks 1 dikelompokkan, yang sebenarnya diperlukan karena tidak seperti indeks nonclustered pada tabel, kesalahan akan dihasilkan jika pembuatan indeks nonclustered pada tampilan diupayakan tanpa terlebih dahulu memiliki indeks cluster.
Indeks ke-2 adalah indeks nonclustered, yang digunakan sebagai indeks di balik kueri. Di bagian komentar dari jawabannya, saya bertanya apa yang akan terjadi jika indeks berkerumun digunakan bukan indeks yang tidak dikelompokkan.
Analisis berikut mencoba menjawab pertanyaan ini.
Saya menggunakan kode yang sama persis, kecuali saya tidak membuat indeks nonclustered pada tampilan.
Saya juga tidak membuat objek statistik. Jika Anda mengikuti dan menggunakan SQL Server Management Studio (SSMS) untuk memasukkan kode di bawah ini, Anda harus sadar bahwa Anda mungkin melihat beberapa garis berlekuk merah - yang terlihat seperti kesalahan. Ini (mungkin) bukan kesalahan, tetapi melibatkan masalah dengan intellisense.
Anda dapat menonaktifkan intellisense atau mengabaikan kesalahan dan menjalankan perintah. Mereka harus menyelesaikan tanpa kesalahan.
Rencana eksekusi berikut (tanpa tampilan / tampilan indeks) dibuat setelah kueri berikut dijalankan terhadap tabel:
Ini memberikan dasar untuk membandingkan. Perhatikan bahwa setelah kueri selesai, objek statistik dibuat (_WA_Sys_00000003_1FCDBCEB). Objek statistik PK_PersistedViewTest dibuat ketika indeks tabel berkerumun dibuat.
Selanjutnya, tampilan yang difilter dan indeks yang dikelompokkan pada tampilan tersebut dibuat:
Sekarang, mari kita coba jalankan kueri lagi, tapi kali ini bertentangan dengan pandangan:
Rencana eksekusi baru sekarang:
Jika rencana baru dapat dipercaya, setelah penambahan tampilan dan indeks berkerumun pada tampilan itu, statistik muncul untuk menunjukkan bahwa waktu yang diperlukan untuk menjalankan kueri kini telah berlipat ganda. Juga, perhatikan bahwa tidak ada objek statistik baru yang dibuat untuk mendukung indeks baru setelah kueri dijalankan, yang berbeda dari kueri pada tabel.
Rencana kueri masih menyarankan bahwa pembuatan indeks yang tidak tercakup akan sangat membantu dalam meningkatkan kinerja kueri. Jadi, apakah itu berarti bahwa indeks nonclustered harus ditambahkan ke tampilan sebelum peningkatan kinerja yang diinginkan dapat diperoleh? Ada satu hal terakhir untuk dicoba. Ubah kueri untuk menggunakan opsi "WITH NOEXPAND":
Ini menghasilkan rencana permintaan berikut:
Rencana eksekusi ini terlihat sangat mirip dengan yang dihasilkan dengan indeks nonclustered yang diberikan dalam jawaban Max Vernon. Tapi, ini dilakukan dengan satu indeks lebih sedikit (nonclustered) dan satu objek statistik kurang.
Ternyata opsi NOEXPAND harus digunakan dengan versi SQL Server express dan standar untuk memanfaatkan tampilan indeks. Paul White memiliki artikel bagus yang menguraikan manfaat menggunakan opsi NOEXPAND. Dia juga merekomendasikan opsi ini digunakan dengan edisi perusahaan untuk memastikan jaminan keunikan yang diberikan oleh indeks tampilan digunakan oleh pengoptimal.
Analisis di atas dilakukan dengan edisi ekspres SQL Sever 2014. Saya juga mencobanya dengan edisi pengembang SQL Server 2016. Opsi NOEXPAND tampaknya tidak diperlukan dengan edisi pengembangan untuk mencapai peningkatan kinerja, tetapi masih disarankan .
Kurang dari 5 bulan lalu, Microsoft membuat edisi pengembang gratis . Lisensi membatasi penggunaan hanya untuk pengembangan, yang berarti database tidak dapat digunakan dalam lingkungan produksi. Jadi, jika Anda mencari untuk menguji tabel yang dioptimalkan memori, enkripsi, R, dll. Maka Anda tidak lagi memiliki alasan tanpa lisensi. Saya berhasil menginstalnya di komputer saya beberapa hari yang lalu bersama SQL Server 2014 Express tanpa masalah.
sumber