Apa efek dari mengganti indeks dengan indeks yang difilter (bukan nilai nol)?

10

Proyek kami menjalankan basis data yang sangat besar, sangat rumit. Jadi sekitar sebulan yang lalu, kami perhatikan bahwa ruang yang digunakan oleh kolom yang diindeks berisi nilai nol menjadi terlalu besar. Sebagai tanggapan terhadap hal itu, saya menulis sebagai skrip yang secara dinamis akan mencari semua indeks satu kolom yang berisi lebih dari 1% dari nilai nol, lalu jatuhkan dan buat kembali indeks tersebut sebagai indeks yang difilter dengan syarat bahwa nilainya TIDAK NULL. Ini akan menjatuhkan dan menciptakan kembali ratusan indeks di seluruh database dan biasanya membebaskan hampir 15% dari ruang yang digunakan oleh seluruh DB.

Sekarang saya punya dua pertanyaan tentang ini:

A) Apa kerugian menggunakan indeks yang difilter dengan cara ini? Saya akan berasumsi bahwa itu hanya akan meningkatkan kinerja, tetapi apakah ada risiko kinerja yang terlibat?

B) Kami menerima kesalahan ( 'tidak dapat menjatuhkan indeks XYZ karena tidak ada atau Anda tidak memiliki izin' ) saat menjatuhkan dan membuat ulang indeks, meskipun saat diperiksa setelahnya, semuanya berjalan persis seperti yang diharapkan. Bagaimana ini bisa terjadi?

Terima kasih atas bantuannya!

Sunting: Menanggapi @Thomas Kejser

Hai dan terima kasih, tetapi ternyata ini adalah bencana. Saat itu kami tidak mengerti beberapa hal seperti:

  1. Selama kueri, SQLOS membuat rencana indeks sebelum menentukan bahwa ia tidak dapat menggunakan nilai NULL untuk bergabung dengan kolom tabel. Yaitu, Anda benar-benar perlu memiliki filter klausa WHERE yang sesuai dengan indeks untuk setiap indeks yang difilter yang digunakan dalam kueri, atau indeks tidak akan digunakan sama sekali.
  2. Menjatuhkan dan membuat indeks dan memperbarui statistik mereka secara berlebihan lagi setelah itu mungkin masih belum cukup untuk menghasilkan rencana yang diperbarui, yang kami asumsikan akan melakukannya. Tampaknya dalam beberapa kasus hanya beban kerja yang cukup tinggi akan memaksa SQL Server untuk menilai kembali rencana.
  3. Ada beberapa eksotik untuk fungsionalitas perencana eksekusi yang sulit ditentukan oleh akal sehat dan logika saja. Dengan ribuan variasi kode-belakang-yang dihasilkan dari permintaan yang berbeda bahkan, indeks yang tampaknya tidak berguna dapat membantu dalam beberapa statistik dan rencana permintaan yang akhirnya digunakan dalam permintaan kritis.

Pada akhirnya, perubahan ini dikembalikan. Jadi indeks yang difilter adalah alat yang ampuh, tetapi Anda harus benar-benar memahami dengan tepat data apa yang diambil dari kolom tersebut. Di mana indeks normal selain dari masalah ruang agak mudah diterapkan, indeks yang difilter mewakili solusi yang sangat khusus. Mereka tentu bukan pengganti untuk indeks reguler, melainkan perpanjangan untuk mereka dalam keadaan khusus yang mereka butuhkan.

Kahn
sumber
Anda mungkin ingin memeriksa kembali strategi pengindeksan Anda juga. Jika Anda memiliki ratusan indeks bidang tunggal, itu mungkin tidak optimal.
JNK
Kebutuhan untuk ini berasal dari fakta bahwa basis data sebagian diwarisi dari sistem lain. Secara default, kami memiliki beberapa tabel abstrak, dan beberapa kolom abstrak yang mungkin tidak digunakan sama sekali, yang menghasilkan sebagian besar nilai NULL yang diindeks dalam jumlah besar. Adapun indeks bidang tunggal, mereka dibuat dari persyaratan dasar bahwa setiap kunci asing harus diindeks, dan banyak dari mereka berada di kolom ini yang berisi sebagian besar atau hanya nilai NULL.
Kahn

Jawaban:

8

Pendekatan yang sangat menarik. Suara positif saya untuk kreativitas.

Karena Anda mendapatkan kembali ruang tersebut, saya menganggap indeks asli sudah tidak ada lagi? Kelemahan dari indeks yang difilter adalah:

Secara praktis, ini berarti Anda harus sangat berhati-hati dengan indeks yang difilter karena akan sering menghasilkan rencana kueri yang mengerikan. Saya tidak akan sampai menyebut mereka tidak berguna, tetapi saya melihatnya sebagai tambahan pada indeks tradisional, bukan sebagai pengganti (seperti yang Anda coba lakukan).

Thomas Kejser
sumber
+ Msgstr "Parameterisasi kueri tidak berfungsi dengan indeks yang difilter". ini mungkin dapat diperbaiki dengan opsi (kompilasi ulang)
MichaelD
2

Thomas Kejser menjawab topik ini di atas.

Saya hanya berpikir tentang menambahkan 2 sen.

Saya telah melihat beberapa indeks yang difilter hanya digunakan (diperlihatkan dalam rencana eksekusi) ketika Anda sama persis dengan klausa di mana dalam kueri Anda sebagai di mana dalam indeks yang difilter.

Sudahkah Anda mencoba menggunakan tampilan yang diindeks ? kolom jarang ?

Saya percaya bahwa sejauh Anda hanya memiliki sambungan dalam, Anda dapat membuat tampilan yang diindeks berisi klausa mana dari indeks yang difilter dan kemudian Anda dapat menggunakan tampilan tersebut.

Mungkin ada lebih dari satu tampilan. Tetapi sama dengan indeks yang tidak berkerumun, terlalu banyak akan memperlambat penulisan Anda.

Dalam pengalaman saya, Anda akan memiliki keuntungan yang baik dalam membaca tetapi Anda harus memantau menulis (sisipan dan pembaruan) khususnya jika tabel terlibat dalam replikasi.

Namun, karena saya mengerti perhatian utama Anda the null valueskarena itu saya akan menyarankan Anda kolom SPARSE dalam indeks Anda .

Kolom jarang sangat cocok untuk indeks yang difilter

Karena saya telah mengiklankan kolom jarang, saya tidak akan merasa baik jika saya tidak memberi tahu Anda tentang batasannya juga:

Saat mendesain tabel dengan kolom jarang, perlu diingat bahwa tambahan 2 byte overhead diperlukan untuk setiap kolom jarang nol di tabel saat baris diperbarui.

Sebagai akibatnya

persyaratan memori tambahan, pembaruan dapat gagal secara tak terduga dengan kesalahan 576 ketika ukuran total baris, termasuk memori ini melebihi 8019,

dan tidak ada kolom yang bisa didorong keluar dari barisan.

Perhatikan contoh tabel yang memiliki 600 kolom tipe bigint yang jarang.

Jika ada 571 kolom non-null, maka ukuran total pada disk adalah 571 * 12 = 6852 byte. Setelah menyertakan overhead baris tambahan dan header kolom jarang, ini meningkat menjadi sekitar 6895 byte. Halaman ini masih memiliki sekitar 1124 byte pada disk. Ini dapat memberi kesan bahwa kolom tambahan dapat diperbarui dengan sukses. Namun, selama pembaruan, ada overhead tambahan dalam memori yang 2 * (jumlah kolom jarang nol). Dalam contoh ini, termasuk overhead tambahan - 2 * 571 = 1142 byte - meningkatkan ukuran baris pada disk menjadi sekitar 8.037 byte. Ukuran ini melebihi ukuran maksimum yang diijinkan 8019 byte. Karena semua kolom adalah tipe data panjang tetap, mereka tidak dapat didorong keluar dari baris. Akibatnya, pembaruan gagal dengan kesalahan 576.

lebih detail tentang tautan di atas, namun saya lebih suka memposting di sini peringatan ini juga:

Mengubah kolom dari jarang menjadi nonsparse atau nonsparse menjadi jarang memerlukan perubahan format penyimpanan kolom.

Mesin Database SQL Server menggunakan prosedur berikut untuk melakukan perubahan ini:

1 - Menambahkan kolom baru ke tabel dalam ukuran dan format penyimpanan baru.

2 - Untuk setiap baris dalam tabel, perbarui dan salin nilai yang disimpan di kolom lama ke kolom baru.

3 - Menghapus kolom lama dari skema tabel.

4 - Membangun kembali tabel (jika tidak ada indeks berkerumun) atau membangun kembali indeks berkerumun untuk merebut kembali ruang yang digunakan oleh kolom lama.

Marcello Miorelli
sumber
1
Hai. Agak terlambat ke medan perang tetapi ya, sementara kami meninggalkan pendekatan yang dijelaskan dalam topik ini sejak lama, kami baru saja kembali ke sana dengan pendekatan yang lebih selektif. Pada dasarnya, kami melihat penggunaan statistik dan model bisnis untuk mengonfirmasi indeks berdasarkan tabel per tabel. Kemudian mengujinya dengan menambahkan indeks yang difilter baru di sisi yang normal, dan memeriksa untuk melihat selama beberapa minggu mana yang akhirnya digunakan. Setelah mengkonfirmasi bahwa HANYA indeks yang difilter digunakan dalam rencana baru, kami menjatuhkan yang tidak berfilter normal.
Kahn
1
Kami juga mengubah beberapa kolom menjadi tipe yang jarang. Namun masalah dengan itu adalah bahwa seperti yang akan Anda lihat dari MSDN, mengubah tipe kolom menjadi jarang pada dasarnya memaksa seluruh indeks berkerumun untuk dibuat kembali. Membuat ini agak berat untuk meja yang besar dan rumit. Jadi kami mengganti nama batasan dan tabel, membuat yang baru dengan model dan nama asli yang sama tetapi dengan kolom jarang, dan kemudian mentransfer data ke tabel baru dalam kumpulan yang sesuai. Kemudian, sekali memeriksa bahwa semuanya baik-baik saja dan semua indeks dan FK lagi di tempat, menjatuhkan tabel lama.
Kahn
1
Juga, dalam beberapa kasus menggunakan kompresi halaman jauh lebih disukai, jadi kami akhirnya melakukan itu. Ini juga berguna karena Anda cukup membuat indeks berkerumun yang ada dengan DROP_EXISTING = ON, untuk membuatnya jauh, jauh lebih cepat daripada pergi dengan rute jarang. Terutama karena ia menghindari seluruh kerumitan mengelola kembali indeks dan FK.
Kahn