Bagaimana pengoptimal SQL Server memperkirakan jumlah baris dalam tabel bergabung?

13

Saya menjalankan kueri ini di basis data AdventureWorks2012 :

SELECT 
    s.SalesOrderID,
    d.CarrierTrackingNumber,
    d.ProductID,
    d.OrderQty
FROM Sales.SalesOrderHeader s 
JOIN Sales.SalesOrderDetail d 
    ON s.SalesOrderID = d.SalesOrderID
WHERE s.CustomerID = 11077

Jika saya melihat perkiraan rencana eksekusi, saya melihat yang berikut:

masukkan deskripsi gambar di sini

Pencarian indeks awal (kanan atas) menggunakan indeks IX_SalesOrderHeader_CustomerID dan mencari pada literal 11077. Ia memiliki perkiraan 2,6192 baris.

masukkan deskripsi gambar di sini

Jika saya menggunakan DBCC SHOW_STATISTICS ('Sales.SalesOrderHeader', 'IX_SalesOrderHeader_CustomerID') WITH HISTOGRAM, ini menunjukkan bahwa nilai 11077 adalah antara dua kunci sampel 11019 dan 11091.

masukkan deskripsi gambar di sini

Jumlah rata-rata baris berbeda antara 11019 dan 11091 adalah 2,619718, atau dibulatkan menjadi 2,61972 yang merupakan nilai estimasi baris yang ditampilkan untuk pencarian indeks.

Bagian yang saya tidak mengerti adalah perkiraan jumlah baris untuk pencarian indeks berkerumun terhadap tabel SalesOrderDetail.

masukkan deskripsi gambar di sini

Jika saya menjalankan DBCC SHOW_STATISTICS ('Sales.SalesOrderDetail', 'PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID'):

masukkan deskripsi gambar di sini

Jadi kepadatan SalesOrderID (yang saya gabungkan) adalah 3.178134E-05. Itu berarti 1 / 3.178134E-05 (31465) sama dengan jumlah nilai unik SalesOrderID dalam tabel SalesOrderDetail.

Jika ada 31465 SalesOrderID unik dalam SalesOrderDetail, maka dengan distribusi genap, jumlah rata-rata baris per SalesOrderID adalah 121317 (total jumlah baris) dibagi dengan 31465. Rata-rata adalah 3,85561

Jadi, jika perkiraan jumlah baris yang akan dilewati adalah 2,61972, dan rata-rata yang akan dikembalikan pada 3,85561, saya akan berpikir perkiraan jumlah baris akan menjadi 2,61972 * 3,85561 = 10,10062.

Namun perkiraan jumlah baris adalah 11,4867.

Saya pikir pemahaman saya tentang estimasi kedua tidak benar dan angka yang berbeda tampaknya menunjukkan hal itu. Apa yang saya lewatkan?

8kb
sumber

Jawaban:

20

Saya pikir pemahaman saya tentang estimasi kedua tidak benar dan angka yang berbeda tampaknya menunjukkan hal itu. Apa yang saya lewatkan?

Menggunakan penaksir kardinalitas SQL Server 2012, selektivitas bergabung mendorong perkiraan jumlah baris di bagian dalam loop bersarang bergabung, dan bukan sebaliknya.

Angka 11,4867 diturunkan (untuk ditampilkan dalam showplan) dengan membagi perkiraan kardinalitas yang dihitung dari output gabungan (30,0919) dengan jumlah iterasi (2,61972). Hasilnya, menggunakan aritmatika floating-point presisi tunggal, adalah 11,4867 .

Ini benar-benar sesederhana itu. Perhatikan bahwa selektivitas join (logis) tidak tergantung pada pilihan operator join fisik. Tetap sama apakah join pada akhirnya dilakukan dengan menggunakan operator fisik Nested Loops, Hash, atau Merge Join.

Dalam SQL Server 2012 dan sebelumnya, selektivitas bergabung (secara keseluruhan) diperkirakan menggunakan SalesOrderIDhistogram dari setiap tabel (dihitung untuk setiap langkah histogram, setelah penyelarasan batas langkah menggunakan interpolasi linier jika diperlukan). The SalesOrderIDhistogram yang berhubungan dengan SalesOrderHeadertabel juga disesuaikan untuk efek skala dari independen CustomerIDfilter.

Bukan berarti ada sesuatu yang pada dasarnya 'salah' dengan perhitungan alternatif yang diajukan dalam pertanyaan; itu hanya membuat serangkaian asumsi yang berbeda. Akan selalu ada berbagai cara untuk menghitung atau menggabungkan perkiraan untuk urutan operasi logis tertentu. Tidak ada jaminan umum bahwa berbagai metode statistik yang diterapkan pada data yang sama akan menghasilkan jawaban yang sama, atau bahwa satu metode akan selalu lebih unggul dari yang lain. Ketidakkonsistenan yang dihasilkan dari penerapan metode statistik yang berbeda bahkan dapat muncul dalam satu rencana pelaksanaan akhir tunggal, meskipun jarang diperhatikan.

Sebagai catatan tambahan, penaksir kardinalitas SQL Server 2014 mengambil pendekatan berbeda untuk menggabungkan informasi histogram yang disesuaikan dengan filter independen ( "penyelarasan kasar" ), yang menghasilkan estimasi akhir berbeda dari 10,1006 baris untuk kueri ini:

Plan for computation:

  CSelCalcExpressionComparedToExpression
  (QCOL: [s].SalesOrderID x_cmpEq QCOL: [d].SalesOrderID)

Loaded histogram for column QCOL: [s].SalesOrderID from stats with id 1
Loaded histogram for column QCOL: [d].SalesOrderID from stats with id 1

Stats collection generated: 

  CStCollJoin(ID=4, **CARD=10.1006** x_jtInner)
      CStCollFilter(ID=3, CARD=2.61972)
          CStCollBaseTable(ID=1, CARD=31465 TBL: Sales.SalesOrderHeader AS TBL: s)
      CStCollBaseTable(ID=2, CARD=121317 TBL: Sales.SalesOrderDetail AS TBL: d)

Ini terjadi menjadi hasil yang sama dengan perhitungan dalam pertanyaan, meskipun alasan rinci berbeda (yaitu tidak didasarkan pada implementasi asumsi loop bersarang).

Paul White 9
sumber