Оптимизация производительности запросов T- SQL - PullRequest
0 голосов
/ 20 января 2020

Этот запрос показывает, сколько украденных и найденных автомобилей было в зависимости от округа и диапазона дат. У меня есть запрос, который работает с небольшими наборами данных, но когда я запускаю его на реальных данных (несколько миллионов записей), он выполняется слишком долго. Мне было интересно, есть ли другой способ, которым я мог бы написать этот запрос, чтобы быть более эффективным. Я думаю, что моя проблема в том, когда я присоединяюсь к таблице агентства с помощью «или», чтобы сравнить первичные ключи агентства с таблицей краж. Любой вклад будет оценен.

    Thefts Table:                                                  County Table:        Agency Table:

    TheftAgencyPK: TheftDate:  RecoveryAgencypk: RecoveryDate:     PK:    Name:        PK  Name:
          1        2019-05-01          1         2019-05-02         1    Sacramento    1   SacPD 
          1        2019-05-02          2         2019-05-04         2    Aptos         2   AptosPD 
          1        2019-05-03          1         2019-05-05
          2        2019-05-05          1         2019-05-09
          1        2019-01-01          2         2019-05-01
Select 
    sub.CountyName 
    ,Sum(Case When sub.TheftDate Between '2019-01-01' and '2019-05-31' and sub.Agency = sub.TheftAgency Then 1  Else 0 End) As Thefts 
    ,Sum(Case When sub.RecoveryDate Between '2019-01-01' and '2019-05-31' and sub.Agency = sub.RecoveryAgency then 1 else 0 end) as Recoveries
From
    (Select 
         Theft.TheftDate as TheftDate, Theft.TheftAgencyPK as TheftAgency,  
         Theft.RecoveryDate as RecoveryDate, 
         Theft.RecoveryAgencyPK as RecoveryAgency, Agency.pk as Agency, 
         County.PK as CountyPK, County.name as CountyName 
     From 
         Thefts Theft
     Left Join 
         Agency Agency on Agency.pk = Theft.TheftAgencyPK or Agency.pk = Theft.RecoveryAgencyPK
     Inner Join 
         County County on County.PK = Agency.pk
     Where 
         TheftDate between '2019-01-01' and '2019-05-31' 
         or RecoveryDate between '2019-01-01' and '2019-05-01') Sub
Group By 
    sub.CountyName

Вывод:

   CountyName:     Thefts:      Recoveries:
   ----------------------------------------
      Aptos           1             2
      Sacramento      4             3

1 Ответ

0 голосов
/ 20 января 2020

Вы можете удалить OR, изменив структуру вашего SQL. Однако я не уверен, что на самом деле означает ваш результат. Вы суммируете по округу, с агентством по взысканию и агентством по кражам, однако, вы сравниваете его с колонкой «агентство», которая взята в основном из аварийного состояния. а затем восстанавливает PR-агентство, а затем суммирует его по округам, по которым в округе была совершена кража и в каком округе восстановлено, как при. Это гарантирует, что результатом будет pr county.

SELECT
    County.Name
    ,sum(a.Thefts) Thefts
    ,sum(a.Recoveries) Recoveries
FROM (SELECT
        Theft.TheftAgencyPK AS Agency
       ,COUNT(*) Thefts
       ,0 AS Recoveries
    FROM Thefts Theft
    WHERE Theft.TheftDate BETWEEN '2019-01-01' AND '2019-05-31'
    GROUP BY Theft.TheftAgencyPK
    UNION ALL
    SELECT
        Theft.RecoveryAgencyPK AS Agency
       ,0 AS Thefts
       ,COUNT(*) AS Recoveries
    FROM Thefts Theft
    WHERE RecoveryDate BETWEEN '2019-01-01' AND '2019-05-01'
    GROUP BY Theft.RecoveryAgencyPK) a
LEFT JOIN Agency Agency
    ON Agency.pk = a.Agency
INNER JOIN County County
    ON County.PK = Agency.pk

Производительность с Тяжелая работа выполняется в Union All - Если у вас есть индексы в таблице «Кража» для даты кражи и даты восстановления, это может дать вам хорошие результаты.

Это, скорее всего, приведет к двум проходам таблицы «Кражи», что может быть хорошо, в зависимости от размера и стратегии индексации.

Если вы хотите сделать только один проход, вы можете сделать что-то подобное вместо объединения всех, это может заставить оптимизатор сделать только один проход таблицы краж :

SELECT
    IIF(t = 'theft', Theft.TheftAgencyPK, Theft.RecoveryAgencyPK) AS Agency
   ,SUM(IIF(t = 'theft', 1, 0)) AS Thefts
   ,SUM(IIF(t = 'theft', 0, 1)) AS Recoveries
FROM Thefts Theft
INNER JOIN (SELECT
        'theft' t UNION ALL SELECT
        'recovery' t) t
    ON (t = 'theft'
            AND Theft.TheftDate BETWEEN '2019-01-01' AND '2019-05-31')
        OR (t = 'recovery'
            AND Theft.RecoveryDate BETWEEN '2019-01-01' AND '2019-05-31')
GROUP BY IIF(t = 'theft', Theft.TheftAgencyPK, Theft.RecoveryAgencyPK)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...