Ошибка оценки избирательности по простому запросу - PullRequest
0 голосов
/ 20 декабря 2018

Давайте создадим простую таблицу tt, подобную этой

WITH x AS (SELECT n FROM (VALUES (0),(1),(2),(3),(4),(5),(6),(7),(8),(9)) v(n)), t1 AS
(
  SELECT ones.n + 10 * tens.n + 100 * hundreds.n + 1000 * thousands.n + 10000 * tenthousands.n as id  
  FROM x ones,     x tens,      x hundreds,       x thousands,       x tenthousands,       x hundredthousands
)
SELECT  id,
        id % 100 groupby,
        row_number() over (partition by id % 100 order by id) orderby,
        row_number() over (partition by id % 100 order by id) / (id % 100 + 1) local_search
INTO tt
FROM t1

У меня есть простой запрос Q1:

select distinct g1.groupby,
        (select count(*) from tt g2 
         where local_search = 1 and g1.groupby = g2.groupby) as orderby
from tt g1
option(maxdop 1)

Я хотел бы знать, почему оценки SQL Serverразмер результата так плохо для Q1 (см. экран печати).Большинство операторов в плане запроса оцениваются точно, однако в корневом операторе Hash Match вводятся совершенно безумные догадки.

enter image description here

Чтобы сделать его более интересным, я пробовал различные переписывания Q1.Если я применяю декорреляцию подзапроса, я получаю эквивалентный запрос Q2:

select main.groupby, 
       coalesce(sub1.orderby,0) orderby
from
(
    select distinct g1.groupby
    from tt g1
) main
left join
(
    select groupby, count(*) orderby
    from tt g2 
    where local_search = 1
    group by groupby
) sub1 on sub1.groupby = main.groupby
option(maxdop 1)

Этот запрос интересен в двух аспектах: (1) оценка является точной (см. Экран печати), (2) она также отличаетсяплан запроса, который более эффективен, чем план запроса Q1.

enter image description here

Итак, вопрос: почему оценка Q1 невернатогда как оценка Q2 является точной? Пожалуйста, не публикуйте другие переписывания этого SQL (я знаю, что это можно написать даже без подзапросов), меня интересует только объяснение поведения оценщика селективности.Спасибо.

1 Ответ

0 голосов
/ 20 декабря 2018

Он не распознает, что значение orderby будет одинаковым для всех строк с одинаковым groupby, поэтому он считает, что distinct groupby, orderby будет иметь больше комбинаций, чем просто distinct groupby.

Умножает оценку на DISTINCT orderby (для меня это 35.0367) и оценку на DISTINCT groupby (для меня это 100), как если бы они были некоррелированными.

Я получаю оценку для 3503.67 для корневого узла в Q1

Это переписывание позволяет избежать этого, поскольку теперь оно группируется только по одному столбцу groupby.

SELECT groupby,
       max(orderby) AS orderby
FROM   (SELECT g1.groupby,
               (SELECT count(*)
                FROM   tt g2
                WHERE  local_search = 1
                       AND g1.groupby = g2.groupby) AS orderby
        FROM   tt g1) d
GROUP  BY groupby
OPTION(maxdop 1) 

Это неоптимальный подход к этому запросу, как показано вашим Q2 и комментарием @ GarethD , о неэффективности многократного выполнения коррелированного подзапроса и отбрасывания дубликатов.

...