SQL запрос выполняется медленно из-за функций даты - PullRequest
0 голосов
/ 16 марта 2020

Я выполняю запрос с использованием Management Studio 18 к базе данных SQL сервера, и для его запуска на сервере требуется 3-4 минуты. Если я удаляю функции дат, то она запускается на моей машине за 1 минуту, но мне нужна функция дат. Кто-нибудь сможет помочь? Заранее спасибо!

Вот оригинальный запрос, который занимает 3-4 на сервере:

With A AS 
(
Select          DSS.transactionSynchronizationId, DSS.transactionDate, DSS.transactionTime,
                convert (varchar, CAST(DateAdd(minute, DateDiff(minute, 0, DSS.transactionTime), 0) AS smalldatetime), 24) As DSS_TransactionTime_EST, DSS.processedBy, 
                DSS.transactionType, DSS.country, DSS.state, DSS.partner,
                DSS.originUnitPrice, DSS.discount, DSS.taxAmount, 
                Case When transactionType In ('REFUND', 'CHARGEBACK', 'CREDIT') Then (DSS.taxAmount*-1) Else DSS.taxAmount End As DSS_Tax_Amount,
                Case When DSS.country In ('US', 'PR', 'CA') And transactionType In ('REFUND', 'CHARGEBACK', 'CREDIT') Then -DSS.originUnitPrice - DSS.discount 
                When DSS.country In ('US', 'PR', 'CA') And transactionType Not In ('REFUND', 'CHARGEBACK', 'CREDIT') Then DSS.originUnitPrice - DSS.discount
                When DSS.country Not In ('US', 'PR', 'CA') And transactionType In ('REFUND', 'CHARGEBACK', 'CREDIT') Then (-DSS.originUnitPrice - DSS.discount - DSS.taxAmount)
                Else DSS.originUnitPrice - DSS.discount - DSS.taxAmount End AS DSS_Gross_Sales
From TableA As DSS
),
C As
(
Select Distinct VTX.[Transaction Synchronization ID], VTX.[Transaction Process Date], VTX.[Transaction Process Time],
                convert(varchar, DATEADD (HOUR , -5 , [Transaction Process Time]) , 24) As Vertex_TransactionTime_EST, VTX.[Situs Country Code 2], VTX.[Situs Main Division],
                VTX.[Taxpayer Division Code], VTX.[Gross Amount] As VTX_Gross_Amount, Sum (VTX.[Tax Amount]) As VTX_Tax_Amount 
From TableB As VTX

Group By VTX.[Transaction Synchronization ID], VTX.[Transaction Process Date], VTX.[Transaction Process Time], VTX.[Situs Country Code 2], VTX.[Situs Main Division],
                VTX.[Taxpayer Division Code], VTX.[Gross Amount]
),
B As
(
Select          C.[Transaction Synchronization ID], C.[Transaction Process Date], C.[Transaction Process Time],
                convert(varchar, DATEADD (HOUR , -5 , C.[Transaction Process Time]) , 24) As Vertex_TransactionTime_EST, C.[Situs Country Code 2], C.[Situs Main Division],
                C.[Taxpayer Division Code], Sum (C.VTX_Gross_Amount) As VTX_Gross_Amount, Sum (C.VTX_Tax_Amount) As VTX_Tax_Amount 
From C

Group By C.[Transaction Synchronization ID], C.[Transaction Process Date], C.[Transaction Process Time],
                convert(varchar, DATEADD (HOUR , -5 , C.[Transaction Process Time]) , 24), C.[Situs Country Code 2], C.[Situs Main Division],
                C.[Taxpayer Division Code]
)
Select          A.transactionSynchronizationId, B.[Transaction Process Date], B.Vertex_TransactionTime_EST, A.transactionDate, A.DSS_TransactionTime_EST, A.processedBy, A.transactionType,
                B.[Situs Country Code 2], A.country, B.[Situs Main Division], A.state, A.partner, B.[Taxpayer Division Code], B.VTX_Gross_Amount, B.VTX_Tax_Amount, A.originUnitPrice,
                A.discount, A.DSS_Tax_Amount, A.DSS_Gross_Sales, Cast ((A.DSS_Gross_Sales - B.VTX_Gross_Amount) As decimal (10,2)) As 'Gross Sales Diff', 
                A.DSS_Tax_Amount, Cast (A.DSS_Tax_Amount - B.VTX_Tax_Amount As decimal (10,2)) As 'Tax Diff'
From A Join B
On A.transactionSynchronizationId = B.[Transaction Synchronization ID]

Вот запрос, который выполняется быстрее:

With A AS 
(
Select          DSS.transactionSynchronizationId, DSS.transactionDate, DSS.transactionTime,
                convert (varchar, CAST(DateAdd(minute, DateDiff(minute, 0, DSS.transactionTime), 0) AS smalldatetime), 24) As DSS_TransactionTime_EST, DSS.processedBy, 
                DSS.transactionType, DSS.country, DSS.state, DSS.partner,
                DSS.originUnitPrice, DSS.discount, DSS.taxAmount, 
                Case When transactionType In ('REFUND', 'CHARGEBACK', 'CREDIT') Then (DSS.taxAmount*-1) Else DSS.taxAmount End As DSS_Tax_Amount,
                Case When DSS.country In ('US', 'PR', 'CA') And transactionType In ('REFUND', 'CHARGEBACK', 'CREDIT') Then -DSS.originUnitPrice - DSS.discount 
                When DSS.country In ('US', 'PR', 'CA') And transactionType Not In ('REFUND', 'CHARGEBACK', 'CREDIT') Then DSS.originUnitPrice - DSS.discount
                When DSS.country Not In ('US', 'PR', 'CA') And transactionType In ('REFUND', 'CHARGEBACK', 'CREDIT') Then (-DSS.originUnitPrice - DSS.discount - DSS.taxAmount)
                Else DSS.originUnitPrice - DSS.discount - DSS.taxAmount End AS DSS_Gross_Sales
From TableA As DSS
),
C As
(
Select Distinct VTX.[Transaction Synchronization ID], VTX.[Transaction Process Date], VTX.[Transaction Process Time],
                convert(varchar, DATEADD (HOUR , -5 , [Transaction Process Time]) , 24) As Vertex_TransactionTime_EST, VTX.[Situs Country Code 2], VTX.[Situs Main Division],
                VTX.[Taxpayer Division Code], VTX.[Gross Amount] As VTX_Gross_Amount, Sum (VTX.[Tax Amount]) As VTX_Tax_Amount 
From TableB As VTX

Group By VTX.[Transaction Synchronization ID], VTX.[Transaction Process Date], VTX.[Transaction Process Time], VTX.[Situs Country Code 2], VTX.[Situs Main Division],
                VTX.[Taxpayer Division Code], VTX.[Gross Amount]
),
B As
(
Select          C.[Transaction Synchronization ID], C.[Transaction Process Date], C.[Transaction Process Time],
                 C.[Situs Country Code 2], C.[Situs Main Division],
                C.[Taxpayer Division Code], Sum (C.VTX_Gross_Amount) As VTX_Gross_Amount, Sum (C.VTX_Tax_Amount) As VTX_Tax_Amount 
From C

Group By C.[Transaction Synchronization ID], C.[Transaction Process Date], C.[Transaction Process Time],
                  C.[Situs Country Code 2], C.[Situs Main Division],
                C.[Taxpayer Division Code]
)
Select          A.transactionSynchronizationId, B.[Transaction Process Date], A.transactionDate, A.DSS_TransactionTime_EST, A.processedBy, A.transactionType,
                B.[Situs Country Code 2], A.country, B.[Situs Main Division], A.state, A.partner, B.[Taxpayer Division Code], B.VTX_Gross_Amount, B.VTX_Tax_Amount, A.originUnitPrice,
                A.discount, A.DSS_Tax_Amount, A.DSS_Gross_Sales, 
                A.DSS_Tax_Amount, Cast (A.DSS_Tax_Amount - B.VTX_Tax_Amount As decimal (10,2)) As 'Tax Diff'
From A Join B
On A.transactionSynchronizationId = B.[Transaction Synchronization ID]

1 Ответ

0 голосов
/ 16 марта 2020

Что нужно сделать:

  • упростить ваши запросы, наверняка должен быть способ? Кажется, что существует избыточность агрегирования ...
  • запустите план выполнения и выясните, где узкое место
  • попробуйте запустить каждый блок отдельно, вы можете обнаружить, что один занимает значительно больше времени, чем другие
  • покажет структуру вашей таблицы, включая индексы и некоторые примеры данных, вероятно, оптимизатор запросов не сможет использовать преимущества индексов для этого запроса
  • улучшить соглашения об именах : псевдонимы таблиц, такие как A, B, C, не имеют смысла, не сразу понятно, что они представляют, и риск путаницы выше
  • если запрос является частью хранимой процедуры:

    • иногда вы можете использовать переменные вместо сложных выражений (для значений, которые нужно вычислять только один раз)
    • использовать временные таблицы и заполните их в несколько этапов - попытка придумать один CTE может привести к снижению производительности
  • возможно, вы не можете Кроме того, отфильтруйте исходные таблицы с помощью предложений WHERE, трудно сказать, не зная данных и цели, но у меня сложилось впечатление, что вы извлекаете все данные, чтобы затем их агрегировать.

Да, это довольно сложно прочитать для нас и, вероятно, для вас.

Моя непосредственная рекомендация - начать с первого строительного блока, убедитесь, что ваш запрос оптимизируется, использует индексы всякий раз, когда это возможно, и не выбирает больше данных, чем необходимо. Всегда смотрите на план выполнения. При необходимости добавьте индексы, например, по датам, если вы ищете по диапазону дат. Даже одна минута не является приемлемым временем ответа. Это может увеличиваться только по мере того, как ваши наборы данных со временем растут.

Теперь, если вы считаете, что проблемы возникают из-за таких утверждений, как:

convert(varchar, DATEADD (HOUR , -5 , C.[Transaction Process Time]) , 24) As Vertex_TransactionTime_EST,

Если вам это действительно нужно, возможно, попробуйте другие формы, избавиться от конверсии варшаров. Вы только возвращаете HH:mm:ss со смещением часового пояса.

Говоря об этом, я бы сказал, что SQL Сервер имеет функции часового пояса, например TODATETIMEOFFSET или В ВРЕМЕННОЙ ЗОНЕ - приятно знать, что они существуют.

...