Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Kinerja sys.partitions

sys.partitions tampaknya merupakan UNION ALL dari dua set hasil (penyimpanan baris dan penyimpanan kolom) dan sebagian besar kueri saya menghasilkan dua pemindaian sysrowsets. Apakah ada filter yang dapat saya masukkan ke kueri sys.partitions jika saya tahu baris yang saya cari adalah rowstore?

Pertanyaan ini diposkan ke #sqlhelp oleh Jake Manske, dan dibawa ke perhatian saya oleh Erik Darling.

Saya tidak ingat pernah mengalami masalah kinerja dengan sys.partitions . Pikiran awal saya (digaungkan oleh Joey D'Antoni) adalah bahwa filter pada data_compression kolom harus hindari pemindaian yang berlebihan, dan kurangi waktu proses kueri hingga sekitar setengahnya. Namun, predikat ini tidak diturunkan, dan alasannya membutuhkan sedikit pembongkaran.

Mengapa sys.partitions lambat?

Jika Anda melihat definisi untuk sys.partitions , pada dasarnya itulah yang Jake jelaskan – sebuah UNION ALL dari semua partisi columnstore dan rowstore, dengan TIGA referensi eksplisit ke sys.sysrowsets (sumber disingkat di sini):

BUAT LIHAT sys.partitions AS WITH partitions_columnstore(...cols...) AS ( SELECT ...cols..., cmprlevel AS data_compression ... FROM sys.sysrowsets rs OUTER APPLY OpenRowset(TABLE ALUCOUNT, rs .rowsetid, 0, 0, 0) ct-------- *** ^^^^^^^^^^^^^^^^ *** LEFT JOIN sys.syspalvalues ​​cl ... MANA .. .sysconv(bit, rs.status &0x00010000) =1 -- Pertimbangkan hanya indeks dasar columnstore ), partitions_rowstore(...cols...) AS ( SELECT ...cols..., cmprlevel AS data_compression ... FROM sys.sysrowsets rs -------- *** ^^^^^^^^^^^^^^^^ *** KIRI BERGABUNG sys.syspalvalues ​​cl ... WHERE ... sysconv(bit, rs .status &0x00010000) =0 -- Abaikan indeks dasar columnstore dan baris yatim. ) SELECT ...cols... from partitions_rowstore p OUTER APPLY OpenRowset(TABLE ALUCOUNT, p.partition_id, 0, 0, p.object_id) ct union semua SELECT ...cols... FROM partitions_columnstore sebagai P1 LEFT JOIN (SELECT ...cols... FROM sys.sysrowsets rs OUTER APP LY OpenRowset(TABEL ALUCOUNT, rs.rowsetid, 0, 0, 0) ct------- *** ^^^^^^^^^^^^^^ *** ) ... 

Pandangan ini tampaknya berbatu, mungkin karena masalah kompatibilitas ke belakang. Itu pasti bisa ditulis ulang agar lebih efisien, terutama hanya untuk referensi sys.sysrowsets dan TABLE ALUCOUNT objek sekali. Tapi tidak banyak yang bisa Anda atau saya lakukan tentang itu sekarang.

Kolom cmprlevel berasal dari sys.sysrowsets (awalan alias pada referensi kolom akan sangat membantu). Anda akan berharap bahwa predikat terhadap kolom di sana akan terjadi secara logis sebelum OUTER APPLY dan dapat mencegah salah satu pemindaian, tetapi bukan itu yang terjadi. Menjalankan kueri sederhana berikut:

SELECT * FROM sys.partitions AS p INNER JOIN sys.objects AS o ON p.object_id =o.object_id WHERE o.is_ms_shipped =0;

Menghasilkan rencana berikut ketika ada indeks columnstore di database (klik untuk memperbesar):

Rencanakan partisi sys, dengan indeks columnstore yang ada

Dan berikut rencana bila tidak ada (klik untuk memperbesar):

Rencanakan partisi sys, tanpa indeks columnstore yang ada

Ini adalah perkiraan rencana yang sama, tetapi SentryOne Plan Explorer dapat menyorot ketika suatu operasi dilewati saat runtime. Ini terjadi untuk pemindaian ketiga dalam kasus terakhir, tetapi saya tidak tahu apakah ada cara untuk mengurangi jumlah pemindaian runtime itu lebih lanjut; pemindaian kedua terjadi bahkan ketika kueri mengembalikan nol baris.

Dalam kasus Jake, dia memiliki banyak objek, jadi melakukan pemindaian ini bahkan dua kali terlihat, menyakitkan, dan satu kali terlalu banyak. Dan sejujurnya saya tidak tahu apakah TABLE ALUCOUNT , panggilan loopback internal dan tidak terdokumentasi, juga harus memindai beberapa objek yang lebih besar ini beberapa kali.

Melihat kembali ke sumbernya, saya bertanya-tanya apakah ada predikat lain yang dapat diteruskan ke tampilan yang dapat memaksa bentuk rencana, tetapi saya benar-benar tidak berpikir ada sesuatu yang dapat berdampak.

Apakah tampilan lain akan berfungsi?

Namun, kita bisa mencoba pandangan yang berbeda sama sekali. Saya mencari tampilan lain yang berisi referensi ke sys.sysrowsets dan ALUCOUNT , dan ada beberapa yang muncul dalam daftar, tetapi hanya dua yang menjanjikan:sys.internal_partitions dan sys.system_internals_partitions .

sys.internal_partitions

Saya mencoba sys.internal_partitions pertama:

SELECT * FROM sys.internal_partitions AS p INNER JOIN sys.objects AS o ON p.object_id =o.object_id WHERE o.is_ms_shipped =0;

Tapi rencananya tidak jauh lebih baik (klik untuk memperbesar):

Rencanakan untuk sys.internal_partitions

Hanya ada dua pemindaian terhadap sys.sysrowsets kali ini, tetapi pemindaian tetap tidak relevan karena kueri tidak mendekati menghasilkan baris yang kami minati. Kami hanya melihat baris untuk objek terkait columnstore (seperti yang dinyatakan dalam dokumentasi).

sys.system_internals_partitions

Mari kita coba sys.system_internals_partitions . Saya sedikit khawatir tentang ini, karena tidak didukung (lihat peringatannya di sini), tetapi bersabarlah sebentar:

SELECT * FROM sys.system_internals_partitions AS p INNER JOIN sys.objects AS o ON p.object_id =o.object_id WHERE o.is_ms_shipped =0;

Dalam database dengan indeks columnstore, ada pemindaian terhadap sys.sysschobjs , tapi sekarang hanya satu pindai terhadap sys.sysrowsets (klik untuk memperbesar):

Rencanakan sys.system_internals_partitions, dengan indeks columnstore yang ada

Jika kita menjalankan kueri yang sama dalam database tanpa indeks penyimpanan kolom, rencananya akan lebih sederhana, dengan pencarian terhadap sys.sysschobjs (klik untuk memperbesar):

Rencanakan sys.system_internals_partitions, tanpa indeks columnstore yang ada

Namun, ini tidak cukup apa yang kita cari, atau setidaknya tidak seperti apa yang Jake kejar, karena ini juga menyertakan artefak dari indeks columnstore. Jika kita menambahkan filter ini, keluaran aktual sekarang cocok dengan kueri sebelumnya yang jauh lebih mahal:

SELECT * FROM sys.system_internals_partitions AS p INNER JOIN sys.objects AS o ON p.object_id =o.object_id WHERE o.is_ms_shipped =0 AND p.is_columnstore =0 AND p.is_orphaned =0;

Sebagai bonus, pindai terhadap sys.sysschobjs telah menjadi pencarian bahkan di database dengan objek columnstore. Sebagian besar dari kita tidak akan melihat perbedaan itu, tetapi jika Anda berada dalam skenario seperti Jake, Anda mungkin (klik untuk memperbesar):

Paket yang lebih sederhana untuk sys.system_internals_partitions, dengan filter tambahan

sys.system_internals_partitions memperlihatkan kumpulan kolom yang berbeda dari sys.partitions (beberapa benar-benar berbeda, yang lain memiliki nama baru) jadi, jika Anda menggunakan output hilir, Anda harus menyesuaikannya. Anda juga ingin memvalidasi bahwa ia mengembalikan semua informasi yang Anda inginkan di seluruh indeks rowstore, memori yang dioptimalkan, dan columnstore, dan jangan lupa tentang tumpukan sial itu. Dan, akhirnya, bersiaplah untuk meninggalkan s di internals banyak, berkali-kali.

Kesimpulan

Seperti yang saya sebutkan di atas, tampilan sistem ini tidak didukung secara resmi, sehingga fungsinya dapat berubah sewaktu-waktu; itu juga bisa dipindahkan di bawah Dedicated Administrator Connection (DAC), atau dihapus dari produk sama sekali. Jangan ragu untuk menggunakan pendekatan ini jika sys.partitions tidak bekerja dengan baik untuk Anda tetapi, tolong, pastikan Anda memiliki rencana cadangan. Dan pastikan itu didokumentasikan sebagai sesuatu yang Anda uji regresi saat Anda mulai menguji versi SQL Server mendatang, atau setelah Anda memutakhirkan, untuk berjaga-jaga.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Menggunakan Tabel Konfigurasi untuk Menentukan Alur Kerja yang Sebenarnya

  2. Tampilan SQL:Bagaimana cara bekerja dengan Tampilan dalam SQL?

  3. Bagaimana Menghubungkan Database ke Python

  4. Memvisualisasikan Tipping Point dengan Plan Explorer

  5. Menggunakan Geekbench 3 untuk Mengevaluasi Kinerja Server Database