Фильтрация одного и того же запроса 3 разных раза. Представление? - PullRequest
0 голосов
/ 07 апреля 2020

У меня очень медленный запрос. Я опубликую здесь псевдокод.

SELECT 
    ListofDates.Date as Event,
    (SELECT COUNT(DISTINCT TableofExtensiveJoins1.ID)
     FROM TableofExtensiveJoins1)
    WHERE Event=TableofExtensiveJoins1.Date AND Condition1
   (SELECT COUNT(DISTINCT TableofExtensiveJoins2.ID)
    FROM TableofExtensiveJoins2
    WHERE Event = TableofExtensiveJoins2.Date AND Condition2)
   (SELECT COUNT(DISTINCT TableofExtensiveJoins3.ElementID)
    FROM TableofExtensiveJoins3
    WHERE Event = TableofExtensiveJoins3.Date AND Condition3)
FROM
    ListOfDates

Здесь следует заметить, что TableOfExtensiveJoins1, 2 и 3 - это абсолютно одинаковые запросы. Но условие «Где» у каждого разное. Выполнение одного и того же запроса 3 раза просто для 3-разной фильтрации кажется немного сложным. Но, как вы можете видеть, это необходимо, потому что я хочу считать вещи на столе. Таблица каждый раз фильтруется по-разному. Но из-за «счета» у меня есть страх, что SQL компилирует таблицу каждый раз снова.

У меня есть этот страх, потому что запрос выполняется исключительно долго. Подзапросы сами по себе действительно сложны. Для примера: получение только одной записи основного запроса занимает около 15 секунд. Сам подзапрос занимает 5 секунд, что объясняет 15 секунд, 3 * 5 = 15. И чтобы выполнить весь основной запрос, он, вероятно, получит несколько тысяч записей. Я позволил ему бежать 50 минут один день, и он не закончился sh. Очевидно, это не линейно, но это не относится к делу. Я просто хотел подчеркнуть, насколько плох запрос.

Так что, очевидно, мне нужно повысить производительность этого запроса. Ради оптимизации допустим, я не могу создавать новые таблицы в базе данных. Остальное было бы легко, я думаю. Предположим также, что TableoExtensiveJoins уже оптимизирован.

Итак, мой вопрос здесь, как я могу переписать запрос, чтобы выполнить его быстрее. Скомпилируйте таблицу один раз, а затем запустите фильтр при компиляции. Запрос выполняется в Microsoft SQL Reporting Services. Таким образом, может быть ограничение на то, какой тип запроса может выполняться. Но я не уверен на 100% в этом.

Редактировать: желаемый результат может быть полезным для правильного ответа.

TableOfExtensiveJoins - это в основном таблица событий. Когда-нибудь что-то определенное c происходит (не имеет значения), создается новая запись.

Теперь я хочу, чтобы по любой дате подсчитывалось количество событий с определенными условиями. ListOfDates имеет список дат. Он принимает первый случай события, а затем создает список дат, который затем фильтруется с помощью Day (Date)% 5 = 1. Так что каждые 5. дата.

Ответы [ 3 ]

0 голосов
/ 07 апреля 2020

Нижеследующее должно работать лучше, так как оно оценивает TableofExtensiveJoins только один раз и требует только одну операцию, чтобы получить отчетливые значения

WITH DistCounts
     AS (SELECT COUNT(DISTINCT ID) AS DistCount,
                condition_flag,
                Date
         FROM   TableofExtensiveJoins
                CROSS APPLY (SELECT 1 WHERE  Condition1
                             UNION ALL
                             SELECT 2 WHERE  Condition2
                             UNION ALL
                             SELECT 3 WHERE  Condition3) CA(condition_flag)
         GROUP  BY condition_flag,
                   Date),
     Pivoted
     AS (SELECT Date,
                MAX(CASE WHEN condition_flag = 1 THEN DistCount END) AS DistCount1,
                MAX(CASE WHEN condition_flag = 2 THEN DistCount END) AS DistCount2,
                MAX(CASE WHEN condition_flag = 3 THEN DistCount END) AS DistCount3
         FROM   DistCounts
         GROUP  BY Date)
SELECT lod.Date as Event,
        DistCount1,
        DistCount2,
        DistCount3
from ListOfDates lod
left join Pivoted p on lod.Date=p.Date
0 голосов
/ 07 апреля 2020

Я думаю, что вы хотите OUTER APPLY:

SELECT lod.Date as Event, tej.*
From ListOfDates lod OUTER APPLY
     (SELECT SUM(CASE WHEN <condition 1> THEN 1 ELSE 0 END) as col1,
             SUM(CASE WHEN <condition 2> THEN 1 ELSE 0 END) as col2,
             SUM(CASE WHEN <condition 3> THEN 1 ELSE 0 END) as col3
      FROM TableofExtensiveJoins tej
      WHERE lod.Event = tej.Date
     ) tej;

Если предположить, что tej.ID уникален, вам не нужен COUNT(DISTINCT). Однако, если вы сделаете:

SELECT lod.Date as Event, tej.*
From ListOfDates lod OUTER APPLY
     (SELECT COUNT(DISTINCT CASE WHEN <condition 1> THEN tej.ID END) as col1,
             COUNT(DISTINCT CASE WHEN <condition 2> THEN tej.ID END) as col2,
             COUNT(DISTINCT CASE WHEN <condition 3> THEN tej.ID END) as col3
      FROM TableofExtensiveJoins tej
      WHERE lod.Event = tej.Date
     ) tej;

Это обобщает все условия, которые могут возникнуть в подзапросах. В качестве бонуса боковые объединения (технический термин для того, что делает APPLY в этом случае) часто имеют лучшую производительность в SQL Server.

0 голосов
/ 07 апреля 2020

Попробуйте условное агрегирование, вид

SELECT ListofDates.Date as Event,
        COUNT(DISTINCT CASE WHEN Condition 1 THEN tej.ID END) cnt1,
        COUNT(DISTINCT CASE WHEN Condition 2 THEN tej.ID END) cnt2,
        COUNT(DISTINCT CASE WHEN Condition 3 THEN tej.ID END) cnt3
from ListOfDates lod
left join TableofExtensiveJoins tej on lod.Event=tej.Date
group by lod.Event
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...