Saya telah bermain-main menyelidiki ambang batas pengambilan sampel dengan pembaruan statistik pada SQL Server (2012) dan melihat beberapa perilaku yang aneh. Pada dasarnya jumlah baris sampel tampaknya bervariasi dalam beberapa keadaan - bahkan dengan set data yang sama.
Saya menjalankan kueri ini:
--Drop table if exists
IF (OBJECT_ID('dbo.Test')) IS NOT NULL DROP TABLE dbo.Test;
--Create Table for Testing
CREATE TABLE dbo.Test(Id INT IDENTITY(1,1) CONSTRAINT PK_Test PRIMARY KEY CLUSTERED, TextValue VARCHAR(20) NULL);
--Insert enough data so we have more than 8Mb (the threshold at which sampling kicks in)
INSERT INTO dbo.Test(TextValue)
SELECT TOP 1000000 'blahblahblah'
FROM sys.objects a, sys.objects b, sys.objects c, sys.objects d;
--Create Index on TextValue
CREATE INDEX IX_Test_TextValue ON dbo.Test(TextValue);
--Update Statistics without specifying how many rows to sample
UPDATE STATISTICS dbo.Test IX_Test_TextValue;
--View the Statistics
DBCC SHOW_STATISTICS('dbo.Test', IX_Test_TextValue) WITH STAT_HEADER;
Ketika saya melihat output dari SHOW_STATISTICS saya menemukan bahwa "Rows Sampled" bervariasi dengan setiap eksekusi penuh (yaitu, tabel akan dijatuhkan, diciptakan kembali dan dihuni kembali).
Sebagai contoh:
Baris Sampel
- 318618
- 319240
- 324198
- 314154
Harapan saya adalah bahwa angka ini akan sama setiap kali tabelnya identik. By the way, saya tidak mendapatkan perilaku ini jika saya hanya menghapus data dan memasukkannya kembali.
Itu bukan pertanyaan kritis, tapi saya akan tertarik untuk memahami apa yang terjadi.
sumber
318618 = 1142*279
,319240 = 1144*279 + 64
,324198=1162*279
Dan314154=1126
sehingga varians adalah jumlah halaman sampel.Jawaban:
Latar Belakang
Data untuk objek statistik dikumpulkan menggunakan pernyataan formulir:
Anda dapat mengumpulkan pernyataan ini dengan Extended Events atau Profiler (
SP:StmtCompleted
).Kueri pembuatan statistik sering mengakses tabel dasar (bukan indeks yang tidak dikelompokkan) untuk menghindari pengelompokan nilai yang secara alami terjadi pada halaman indeks yang tidak dikluster.
Jumlah baris sampel tergantung pada jumlah seluruh halaman yang dipilih untuk pengambilan sampel. Setiap halaman dari tabel dipilih atau tidak. Semua baris pada halaman yang dipilih berkontribusi pada statistik.
Angka acak
SQL Server menggunakan generator nomor acak untuk memutuskan apakah suatu halaman memenuhi syarat atau tidak. Generator yang digunakan dalam contoh ini adalah generator bilangan acak Lehmer dengan nilai parameter seperti yang ditunjukkan di bawah ini:
Nilai dihitung sebagai jumlah dari:
Xseed
Bagian integer rendah dari
bigint
tabel dasar ( )partition_id
misalnyaNilai yang ditentukan dalam
REPEATABLE
klausaUPDATE STATISTICS
,REPEATABLE
nilainya 1.m_randomSeed
elemen informasi debugging internal metode akses yang ditunjukkan dalam rencana eksekusi ketika jejak jejak 8666 diaktifkan, misalnya<Field FieldName="m_randomSeed" FieldValue="1" />
Untuk SQL Server 2012, perhitungan ini terjadi di
sqlmin!UnOrderPageScanner::StartScan
:di mana memori at
[rcx+30h]
berisi 32 bit id partisi dan memori at[rcx+2Ch]
berisiREPEATABLE
nilai yang digunakan.Generator nomor acak diinisialisasi kemudian dalam metode yang sama, memanggil
sqlmin!RandomNumGenerator::Init
, di mana instruksi:... mengalikan benih dengan
41A7
hex (16807 desimal = 7 5 ) seperti yang ditunjukkan pada persamaan di atas.Kemudian angka acak (untuk masing-masing halaman) dihasilkan dengan menggunakan kode dasar yang sama yang diuraikan dalam
sqlmin!UnOrderPageScanner::SetupSubScanner
.StatMan
Untuk
StatMan
kueri contoh yang ditunjukkan di atas, halaman yang sama akan dikumpulkan seperti untuk pernyataan T-SQL:Ini akan cocok dengan output dari:
Kasing tepi
Salah satu konsekuensi dari menggunakan generator angka acak MINSTD Lehmer adalah bahwa nilai seed nol dan int.max tidak boleh digunakan karena ini akan menghasilkan algoritma yang menghasilkan urutan nol (memilih setiap halaman).
Kode mendeteksi nol, dan menggunakan nilai dari 'jam' sistem sebagai seed dalam kasus itu. Itu tidak melakukan hal yang sama jika seed adalah int.max (
0x7FFFFFFF
= 2 31 - 1).Kita dapat merekayasa skenario ini karena seed awal dihitung sebagai jumlah dari 32 bit yang rendah dari id partisi dan
REPEATABLE
nilainya. TheREPEATABLE
nilai yang akan menghasilkan benih yang int.max dan karena itu setiap halaman yang dipilih untuk sampel adalah:Mengerjakan itu menjadi contoh lengkap:
Itu akan memilih setiap baris pada setiap halaman apa pun
TABLESAMPLE
klausa mengatakan (bahkan nol persen).sumber
Ini adalah pertanyaan yang sangat bagus! Saya akan mulai dengan apa yang saya tahu pasti dan kemudian beralih ke spekulasi. Banyak detail tentang ini di posting blog saya di sini .
Pembaruan statistik sampel digunakan di
TABLESAMPLE
belakang layar. Sangat mudah untuk menemukan dokumentasi tentang hal itu secara online. Namun, saya percaya itu tidak diketahui bahwa baris yang dikembalikanTABLESAMPLE
sebagian tergantung padahobt_id
objek. Ketika Anda menjatuhkan dan membuat ulang objek, Anda mendapatkan yang baruhobt_id
sehingga baris yang dikembalikan secara acak berbeda.Jika Anda menghapus dan memasukkan kembali data
hobt_id
tetap sama. Selama data diletakkan dengan cara yang sama pada disk (pemindaian urutan alokasi mengembalikan hasil yang sama dalam urutan yang sama) maka data sampel tidak boleh berubah.Anda juga dapat mengubah jumlah baris sampel dengan membangun kembali indeks berkerumun di atas meja. Sebagai contoh:
Seperti mengapa itu terjadi, saya percaya itu karena SQL Server memindai indeks berkerumun, bukan indeks yang tidak dikelompokkan saat mengumpulkan statistik sampel pada indeks. Saya juga berpikir bahwa ada nilai tersembunyi (bagi kita yang melacak permintaan pembaruan statistik tersembunyi) untuk
REPEATABLE
digunakan bersamaTABLESAMPLE
. Saya belum membuktikan semua itu, tetapi itu menjelaskan mengapa histogram Anda dan baris sampel berubah dengan pembangunan kembali indeks berkerumun.sumber
Saya melihat ini di dalam Microsoft SQL Server 2008: T-SQL Querying oleh Itzik Ben-Gan dan saya tidak dapat menambahkannya sebagai komentar jadi saya mempostingnya di sini, saya pikir ini juga menarik bagi orang lain:
Lihat juga Pengambilan Sampel Menggunakan TABLESAMPLE oleh Roji. P. Thomas.
sumber