Выберите время ожидания запроса только для 17000 строк в таблице - PullRequest
0 голосов
/ 11 июля 2019

Мне нужно определить строки, которые при группировке на самом высоком уровне не достигают счетчика, который больше порогового значения.Если строка соответствует пороговому значению на более низком уровне группировки, эти строки не рассматриваются для проверок более высокого уровня.

Например:

У меня есть значение, подобное этому, и порог равен 5.

COL_1   COL_2   COL_3
CH  ZZZZZZ  T77613
CH  ZZZZZZ  R537973
**CH    181600  19M8323**
**CH    HYC440  RE575008**
**CH    211000  AE74215**
CH  ZZZZZZ  T77858
CH  ZZZZZZ  T76938
CH  ZZZZZZ  T77932
CH  ZZZZZZ  T76938
CH  ZZZZZZ  14M7396
CH  ZZZZZZ  RE593267
CH  ZZZZZZ  RE593267
CH  ZZZZZZ  RE579130
CH  ZZZZZZ  14M7296
CH  ZZZZZZ  RE580337
CH  ZZZZZZ  RE580337

необходимо выбирать только выделенные жирным шрифтом строки.

Я использую запрос, подобный приведенному ниже

WITH Step1 AS (
    SELECT x1.*
    FROM mytable AS x1
    LEFT JOIN (
        SELECT col_1
            ,col_2
            ,col_3
        FROM mytable
        GROUP BY col_1
            ,col_2
            ,col_3
        HAVING COUNT(*) >= 5
        ) y1 ON x1.col_1 = y1.col_1
        AND x1.col_2 = y1.col_2
        AND x1.col_3 = y1.col_3
    WHERE y1.col_1 IS NULL
        AND y1.col_2 IS NULL
        AND y1.col_3 IS NULL
    )
,Step2 AS (
    SELECT x1.*
    FROM Step1 x1
    LEFT JOIN (
        SELECT col_1
            ,col_2
        FROM Step1
        GROUP BY col_1
            ,col_2
        HAVING COUNT(*) >= 5
        ) y1 ON x1.col_1 = y1.col_1
        AND x1.col_2 = y1.col_2
    WHERE y1.col_1 IS NULL
        AND y1.col_2 IS NULL
    )
,Step3 AS (
    SELECT x1.*
    FROM Step2 x1
    LEFT JOIN (
        SELECT col_1
        FROM Step2
        GROUP BY col_1
        HAVING COUNT(*) >= 5
        ) y1 ON x1.col_1 = y1.col_1
    WHERE y1.col_1 IS NULL
    )
SELECT *
FROM Step3

Этот запрос дает правильные результаты.Но если в таблице более 17000 строк, SQL-запрос просто зависает и время ожидания истекает.

Кто-нибудь знает, что идет не так, и какое лучшее решение можно предложить?

Обновление:

Я нашел несколько ответов здесь https://www.sqlshack.com/why-is-my-cte-so-slow/.После использования временной таблицы для хранения результатов первых двух CTE я смог выполнить запрос и получить результаты за 45 секунд.

WITH Step1 AS (
        SELECT x1.*
        FROM mytable AS x1
        LEFT JOIN (
            SELECT col_1
                ,col_2
                ,col_3
            FROM mytable
            GROUP BY col_1
                ,col_2
                ,col_3
            HAVING COUNT(*) >= 5
            ) y1 ON x1.col_1 = y1.col_1
            AND x1.col_2 = y1.col_2
            AND x1.col_3 = y1.col_3
        WHERE y1.col_1 IS NULL
            AND y1.col_2 IS NULL
            AND y1.col_3 IS NULL
        )
    ,Step2 AS (
        SELECT x1.*
        FROM Step1 x1
        LEFT JOIN (
            SELECT col_1
                ,col_2
            FROM Step1
            GROUP BY col_1
                ,col_2
            HAVING COUNT(*) >= 5
            ) y1 ON x1.col_1 = y1.col_1
            AND x1.col_2 = y1.col_2
        WHERE y1.col_1 IS NULL
            AND y1.col_2 IS NULL
        )

select * into #CTE2 from step2 ;

WITH Step3 AS (
        SELECT x1.*
        FROM #CTE2 x1
        LEFT JOIN (
            SELECT col_1
            FROM Step2
            GROUP BY col_1
            HAVING COUNT(*) >= 5
            ) y1 ON x1.col_1 = y1.col_1
        WHERE y1.col_1 IS NULL
        )
SELECT *
    FROM Step3 ;

Но это означает, что это уже не один SQL-запрос.

1 Ответ

0 голосов
/ 11 июля 2019

Ваше требование не совсем понятно, но, поскольку вы сказали, что ваш запрос дает правильный результат, а ваша проблема - просто производительность, я бы начал заменять эти левые объединения на EXISTS, используя HAVING для получения данных, которые вы уже хочется возвращаться, а не отбрасывать ...

Следующим шагом будет проверка правильности индексации таблицы

 ;WITH 
    Step1 AS ( 
        SELECT * 
        FROM MyTable S1
        WHERE EXISTS (
        SELECT 1
        FROM MyTable 
        WHERE COL_1 = S1.COL_1 AND COL_2 = S1.COL_2 ANd COL_3 = S1.COL_3 
        GROUP BY COL_1, COL_2, COL_3
        HAVING COUNT(*) < 5 )  
    ) , 
    Step2 AS 
    ( 
        SELECT * 
        FROM Step1 S1
        WHERE EXISTS (
        SELECT 1
        FROM Step1 
        WHERE COL_1 = S1.COL_1 AND COL_2 = S1.COL_2
        GROUP BY COL_1,COL_2 
        HAVING COUNT(*) < 5 )
    ) , 
    Step3 AS 
    ( 
        SELECT * 
        FROM Step2 S2
        WHERE EXISTS (
        SELECT 1
        FROM Step2 
        WHERE COL_1 = S2.COL_1
        GROUP BY COL_1 
        HAVING COUNT(*) < 5 )
    ) 
    SELECT * FROM Step3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...