Я хотел знать, какой из следующих двух подходов быстрее:
1) Три COUNT
:
SELECT Approved = (SELECT COUNT(*) FROM dbo.Claims d
WHERE d.Status = 'Approved'),
Valid = (SELECT COUNT(*) FROM dbo.Claims d
WHERE d.Status = 'Valid'),
Reject = (SELECT COUNT(*) FROM dbo.Claims d
WHERE d.Status = 'Reject')
2) SUM
с FROM
-clause:
SELECT Approved = SUM(CASE WHEN Status = 'Approved' THEN 1 ELSE 0 END),
Valid = SUM(CASE WHEN Status = 'Valid' THEN 1 ELSE 0 END),
Reject = SUM(CASE WHEN Status = 'Reject' THEN 1 ELSE 0 END)
FROM dbo.Claims c;
Я был удивлен, что разница такая большая. Первый запрос с тремя подзапросами возвращает результат немедленно, тогда как второй SUM
подход требует 18 секунд.
Claims
это представление, которое выбирает из таблицы, содержащей ~ 18 миллионов строк. В столбце FK есть указатель на ClaimStatus
таблицу, в которой содержится имя-статуса.
Почему это так важно, использую ли я COUNT
или SUM
?
Исполнение-планы:
Всего 12 статусов. Эти три статуса принадлежат 7% всех строк.
Это фактический вид, я не уверен, что это актуально:
CREATE VIEW [dbo].[Claims]
AS
SELECT
mu.Marketunitname AS MarketUnit,
c.Countryname AS Country,
gsp.Gspname AS GSP,
gsp.Wcmskeynumber AS GspNumber,
sl.Slname AS SL,
sl.Wcmskeynumber AS SlNumber,
m.Modelname AS Model,
m.Salesname AS [Model-Salesname],
s.Claimstatusname AS [Status],
d.Work_order AS [Work Order],
d.Ssn_number AS IMEI,
d.Ssn_out,
Remarks,
d.Claimnumber AS [Claim-Number],
d.Rma_number AS [RMA-Number],
dbo.ToShortDateString(d.Received_Date, 1) AS [Received Date],
Iddata,
Fisl,
Fimodel,
Ficlaimstatus
FROM Tabdata AS d
INNER JOIN Locsl AS sl
ON d.Fisl = sl.Idsl
INNER JOIN Locgsp AS gsp
ON sl.Figsp = gsp.Idgsp
INNER JOIN Loccountry AS c
ON gsp.Ficountry = c.Idcountry
INNER JOIN Locmarketunit AS mu
ON c.Fimarketunit = mu.Idmarketunit
INNER JOIN Modmodel AS m
ON d.Fimodel = m.Idmodel
INNER JOIN Dimclaimstatus AS s
ON d.Ficlaimstatus = s.Idclaimstatus
INNER JOIN Tdefproducttype
ON d.Fiproducttype = Tdefproducttype.Idproducttype
LEFT OUTER JOIN Tdefservicelevel
ON d.Fimaxservicelevel = Tdefservicelevel.Idservicelevel
LEFT OUTER JOIN Tdefactioncode AS ac
ON d.Fimaxactioncode = ac.Idactioncode
sql-server
performance
sql-server-2005
t-sql
Тим Шмельтер
источник
источник
COUNT
версию плана. Можете ли вы отредактировать подобное вSUM
версии, чтобы указать правильный план?Authorized
.WHERE c.Status = 'Approved' or c.Status = 'Valid' or c.status = 'Reject'
вSUM
вариант.Ответы:
COUNT(*)
Версия может просто искать в индекс у вас на колонке статуса один раз для каждого состояния , вы выбираете, в то время какSUM(...)
потребности версии для взыщут индексировать двенадцать раз (общее количество уникальных статусов).Очевидно, что поиск индекса в три раза будет быстрее, чем поиск в 12 раз.
Первый план требует предоставления памяти в 238 МБ, тогда как второй план требует предоставления памяти в 650 МБ. Это может быть , что большая субсидия память не может быть немедленно заполнен, делая запрос , который гораздо медленнее.
Измените второй запрос:
Это позволит оптимизатору запросов исключить 75% поисков по индексу, что должно привести как к меньшему требуемому предоставлению памяти, так и к меньшим требованиям ввода-вывода и более быстрому получению времени на результат.
Эта
SUM(CASE WHEN ...)
конструкция по существу не позволяет оптимизатору запросов проталкиватьStatus
предикаты в часть плана поиска индекса.источник
max server memory
опцию - она должна быть настроена на правильное значение для вашей системы. Вы можете посмотреть на этот вопрос и ответы на него, чтобы узнать, как это сделать.