Как оптимизатор SQL Server оценивает количество строк в объединенной таблице?

13

Я выполняю этот запрос в базе данных 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

Если я посмотрю на примерный план выполнения, я увижу следующее:

введите описание изображения здесь

Первоначальный поиск по индексу (вверху справа) использует индекс IX_SalesOrderHeader_CustomerID и осуществляет поиск по литералу 11077. Его оценка составляет 2,6192 строки.

введите описание изображения здесь

Если я использую DBCC SHOW_STATISTICS ('Sales.SalesOrderHeader', 'IX_SalesOrderHeader_CustomerID') WITH HISTOGRAM, это показывает, что значение 11077 находится между двумя выбранными ключами 11019 и 11091.

введите описание изображения здесь

Среднее число отдельных строк между 11019 и 11091 составляет 2,619718 или округлено до 2,61972, что является значением оценочных строк, показанных для поиска по индексу.

Часть, которую я не понимаю, - это приблизительное количество строк для поиска кластеризованного индекса по таблице SalesOrderDetail.

введите описание изображения здесь

Если я бегу DBCC SHOW_STATISTICS ('Sales.SalesOrderDetail', 'PK_SalesOrderDetail_SalesOrderID_SalesOrderDetailID'):

введите описание изображения здесь

Таким образом, плотность SalesOrderID (к которому я присоединяюсь) составляет 3.178134E-05. Это означает, что 1 / 3.178134E-05 (31465) равно количеству уникальных значений SalesOrderID в таблице SalesOrderDetail.

Если в SalesOrderDetail имеется 31465 уникальных SalesOrderID, то при равномерном распределении среднее число строк на SalesOrderID равно 121317 (общее количество строк), деленное на 31465. Среднее значение составляет 3.85561.

Таким образом, если предполагаемое количество строк, подлежащих циклу, равно 2,61972, а среднее значение, которое должно быть возвращено в 3,85561, я думаю, что предполагаемое количество строк будет 2,61972 * 3,85561 = 10,10062.

Но предполагаемое количество строк - 11,4867.

Я думаю, что мое понимание второй оценки неверно, и разные цифры, кажется, указывают на это. Что мне не хватает?

8kb
источник

Ответы:

20

Я думаю, что мое понимание второй оценки неверно, и разные цифры, кажется, указывают на это. Что мне не хватает?

Используя оценщик мощности SQL Server 2012, селективность объединения определяет предполагаемое количество строк на внутренней стороне объединения вложенных циклов, а не наоборот.

Число 11.4867 получается (для отображения в showplan) путем деления вычисленной расчетной мощности вывода соединения (30.0919) на количество итераций (2.61972). Результат с использованием арифметики с плавающей точкой одинарной точности равен 11,4867 .

Это действительно так просто. Обратите внимание, что селективность (логического) соединения не зависит от выбора оператора физического соединения. Остаётся неизменным, выполняется ли объединение с помощью физического оператора Nested Loops, Hash или Merge Join.

В SQL Server 2012 и более ранних версиях селективность объединения (в целом) оценивается с использованием SalesOrderIDгистограмм из каждой таблицы (вычисляется для каждого шага гистограммы после выравнивания границ шага с использованием линейной интерполяции, если необходимо). SalesOrderIDГистограммы , связанные с SalesOrderHeaderтаблицей также корректируются для масштабирования эффекта независимого CustomerIDфильтра.

Это не значит, что в альтернативном расчете, предложенном в этом вопросе, есть что-то принципиально «неправильное»; это просто делает другой набор предположений. Всегда будут разные способы вычисления или объединения оценок для данной последовательности логических операций. Нет общей гарантии, что различные статистические методы, применяемые к одним и тем же данным, будут давать одинаковые ответы или что один метод всегда будет превосходить другой. Несоответствия, возникающие в результате применения различных статистических методов, могут даже появляться в одном окончательном плане выполнения, хотя они редко замечаются.

В качестве дополнительного примечания в оценщике количества элементов SQL Server 2014 используется другой подход к объединению информации гистограммы, скорректированной независимым фильтром ( «грубое выравнивание» ), что приводит к другой окончательной оценке в 10,1006 строк для этого запроса:

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)

Это происходит с тем же результатом, что и вычисление в вопросе, хотя подробные рассуждения отличаются (т.е. он не основан на реализации предполагаемых вложенных циклов).

Пол Уайт 9
источник