Estimasi Kardinalitas untuk> = dan> untuk nilai statistik langkah intra

9

Saya mencoba memahami bagaimana SQL Server mencoba memperkirakan 'lebih dari' dan 'lebih besar dari sama dengan' di mana klausa dalam SQL Server 2014.

Saya pikir saya mengerti perkiraan kardinalitas ketika menyentuh langkah misalnya jika saya lakukan

    select * from charge where charge_dt >= '1999-10-13 10:47:38.550'

Estimasi kardinalitas adalah 6672 yang dapat dengan mudah dihitung sebagai 32 (EQ_ROWS) + 6624 (RANGE_ROWS) + 16 (EQ_ROWS) = 6672 (histogram pada tangkapan layar di bawah)

masukkan deskripsi gambar di sini

Tetapi ketika saya melakukannya

    select * from charge where charge_dt >= '1999-10-13 10:48:38.550' 

(Menambah waktu menjadi 10:48 jadi ini bukan langkah)

perkiraannya adalah 4844,13.

Bagaimana itu dihitung?

jesijesi
sumber

Jawaban:

9

Satu-satunya kesulitan adalah dalam memutuskan bagaimana menangani langkah histogram yang sebagian dicakup oleh interval predikat kueri. Seluruh langkah histogram yang dicakup oleh rentang predikat sepele seperti yang disebutkan dalam pertanyaan.

Penaksir Kardinalitas Warisan

F = fraksi (antara 0 dan 1) dari rentang langkah yang dicakup oleh predikat kueri.

Ide dasarnya adalah menggunakan F(interpolasi linier) untuk menentukan berapa banyak nilai berbeda intra-langkah yang dicakup oleh predikat. Mengalikan hasil ini dengan jumlah rata-rata baris per nilai yang berbeda (dengan asumsi keseragaman), dan menambahkan langkah, baris yang sama memberikan perkiraan kardinalitas:

Kardinalitas = EQ_ROWS + (AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)

Formula yang sama digunakan untuk >dan >=dalam warisan CE.

Penaksir Kardinalitas Baru

CE baru memodifikasi sedikit algoritma sebelumnya untuk membedakan antara >dan >=.

Mengambil >pertama, rumusnya adalah:

Kardinalitas = EQ_ROWS + (AVG_RANGE_ROWS * (F * (DISTINCT_RANGE_ROWS - 1))))

Untuk >=itu adalah:

Kardinalitas = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) +1))

Yang + 1mencerminkan bahwa ketika perbandingan melibatkan kesetaraan, kecocokan diasumsikan (asumsi inklusi).

Dalam contoh pertanyaan, Fdapat dihitung sebagai:

DECLARE 
    @Q datetime = '1999-10-13T10:48:38.550',
    @K1 datetime = '1999-10-13T10:47:38.550',
    @K2 datetime = '1999-10-13T10:51:19.317';

DECLARE
    @QR float = DATEDIFF(MILLISECOND, @Q, @K2), -- predicate range
    @SR float = DATEDIFF(MILLISECOND, @K1, @K2) -- whole step range

SELECT
    F = @QR / @SR;

Hasilnya adalah 0,728219019233034 . Memasukkannya ke dalam rumus untuk >=dengan nilai yang diketahui lainnya:

Kardinalitas = EQ_ROWS + (AVG_RANGE_ROWS * ((F * (DISTINCT_RANGE_ROWS - 1)) +1))
            = 16 + (16.1956 * ((0.728219019233034 * (409 - 1)) + 1))
            = 16 + (16.1956 * ((0.728219019233034 * 408) +1))
            = 16 + (16.1956 * (297.113359847077872 +1))
            = 16 + (16.1956 * 298.113359847077872)
            = 16 + 4828.1247307393343837632
            = 4844.1247307393343837632
            = 4844.12473073933 (untuk presisi mengambang)

Hasil ini setuju dengan perkiraan 4844.13 yang ditunjukkan dalam pertanyaan.

Kueri yang sama menggunakan legacy CE (mis. Menggunakan jejak bendera 9481) akan menghasilkan perkiraan:

Kardinalitas = EQ_ROWS + (AVG_RANGE_ROWS * F * DISTINCT_RANGE_ROWS)
            = 16 + (16.1956 * 0.728219019233034 * 409)
            = 16 + 4823.72307468722
            = 4839.72307468722

Perhatikan bahwa estimasi akan sama untuk >dan >=menggunakan legacy CE.

Paul White 9
sumber
4

Rumus untuk mengestimasi baris menjadi sedikit konyol ketika filter "lebih besar dari" atau "kurang dari", tetapi itu adalah angka yang bisa Anda dapatkan.

Angka-angka

Menggunakan langkah 193, berikut adalah angka yang relevan:

RANGE_ROWS = 6624

EQ_ROWS = 16

AVG_RANGE_ROWS = 16.1956

RANGE_HI_KEY dari langkah sebelumnya = 1999-10-13 10: 47: 38.550

RANGE_HI_KEY dari langkah saat ini = 1999-10-13 10: 51: 19.317

Nilai dari klausa WHERE = 1999-10-13 10: 48: 38.550

Formula

1) Temukan ms antara dua rentang tombol hi

SELECT DATEDIFF (ms, '1999-10-13 10:47:38.550', '1999-10-13 10:51:19.317')

Hasilnya adalah 220767 ms.

2) Sesuaikan jumlah baris

Kita perlu menemukan baris per milidetik, tetapi sebelum kita melakukannya, kita harus mengurangi AVG_RANGE_ROWS dari RANGE_ROWS:

6624 - 16.1956 = 6607.8044 baris

3) Hitung baris per ms dengan jumlah baris yang disesuaikan:

6607.8044 baris / 220767 ms = .0299311 baris per ms

4) Hitung ms antara nilai dari klausa WHERE dan langkah saat ini RANGE_HI_KEY

SELECT DATEDIFF (ms, '1999-10-13 10:48:38.550', '1999-10-13 10:51:19.317')

Ini memberi kita 160767 ms.

5) Hitung baris pada langkah ini berdasarkan pada baris per detik:

.0299311 baris / ms * 160767 ms = 4811,9332 baris

6) Ingat bagaimana kami mengurangi AVG_RANGE_ROWS sebelumnya? Saatnya untuk menambahkannya kembali. Sekarang kita selesai menghitung angka yang terkait dengan baris per detik, kita juga dapat menambahkan EQ_ROWS dengan aman:

4811.9332 + 16.1956 + 16 = 4844.1288

Digabungkan, itulah perkiraan 4844.13 kami.

Menguji formula

Saya tidak dapat menemukan artikel atau posting blog tentang mengapa AVG_RANGE_ROWS dikurangkan sebelum baris per ms dihitung. Saya adalah mampu untuk mengkonfirmasi mereka dicatat dalam perkiraan, tetapi hanya pada milidetik terakhir - secara harfiah.

Dengan menggunakan database WideWorldImporters , saya melakukan beberapa pengujian tambahan dan menemukan penurunan estimasi baris menjadi linier hingga akhir langkah, di mana 1x AVG_RANGE_ROWS tiba-tiba diperhitungkan.

Inilah kueri sampel saya:

SELECT PickingCompletedWhen
FROM Sales.Orders
WHERE PickingCompletedWhen >= '2016-05-24 11:00:01.000000'

Saya memperbarui statistik untuk PickingCompletedWhen, kemudian mendapat histogram:

DBCC SHOW_STATISTICS([sales.orders], '_WA_Sys_0000000E_44CA3770')

Histogram untuk _WA_Sys_0000000E_44CA3770 (3 langkah terakhir)

Untuk melihat bagaimana penurunan baris yang diperkirakan saat kami mendekati RANGE_HI_KEY, saya mengumpulkan sampel di seluruh langkah. Penurunannya linear, tetapi berperilaku seolah-olah sejumlah baris sama dengan nilai AVG_RANGE_ROWS hanya bukan bagian dari tren ... sampai Anda menekan RANGE_HI_KEY dan tiba-tiba mereka turun seperti utang yang tidak tertagih dihapuskan. Anda dapat melihatnya dalam data sampel, terutama dalam grafik.

masukkan deskripsi gambar di sini

Perhatikan penurunan yang stabil dalam baris hingga kami menekan RANGE_HI_KEY dan kemudian BOOM potongan AVG_RANGE_ROWS terakhir tiba-tiba dikurangi. Sangat mudah untuk melihat grafik.

masukkan deskripsi gambar di sini

Singkatnya, perlakuan aneh AVG_RANGE_ROWS membuat penghitungan estimasi baris lebih rumit, tetapi Anda selalu dapat mendamaikan apa yang sedang dilakukan CE.

Bagaimana dengan Backon Eksponensial?

Exponential Backoff adalah metode yang digunakan Cardinality Estimator baru (seperti SQL Server 2014) untuk mendapatkan perkiraan yang lebih baik saat menggunakan beberapa statistik kolom tunggal. Karena pertanyaan ini adalah tentang satu stat satu kolom, itu tidak melibatkan rumus EB.

Doug Lane
sumber