我每月有大约50万条记录。我正在撰写一份报告,需要选择2个月的数据。用户选择了月份,以及之前12个月的数据。
由于我的一些其他选择标准以及这些数据的存储方式,我发现我必须运行相同的查询4次才能获得完整的结果集。这意味着我需要以最佳方式运行代码 - 没有人喜欢等待屏幕显示" loading" ; - )
这是我正在运行的SQL:
Declare @ReportDate DateTime
SET @ReportDate = dateadd(month,-1,DATEADD(month, DATEDIFF(month, 0, sysdatetime()), 0))
CREATE TABLE #DailyVolumes
(contract_name VARCHAR(50),
Volume INT,
date_registered DATETIME
);
INSERT into #DailyVolumes(contract_name, Volume, date_registered)
SELECT
CONCAT('L1-',a.contract_code) AS contract_name
,count(distinct(CONCAT(rtrim(p.lis_xxxx_id), '-', rtrim(r.lis_req_id)))) AS Volume
,a.date_registered
-- Create Temp Table to contain daily data
FROM accession a
Left join xxxx P on a.xxxx_id = p.xxxx_id
Left join requester R on a.requester_id = r.requester_id
where
(([date_registered] >= @ReportDate and [date_registered] < dateadd(month,1,@ReportDate))
OR ([date_registered] >= dateadd(month,-12,@ReportDate) and [date_registered] < dateadd(month,-11,@ReportDate)))
-- Limit results to L1
AND a.lis_code = 'L'
-- Limit results to Visitype NOT I or E
AND visit_type NOT IN('I', 'E')
GROUP BY
CONCAT('L1-',a.contract_code)
,a.date_registered
INSERT into #DailyVolumes(contract_name, Volume, date_registered)
SELECT
CONCAT('L1-',a.contract_code) AS contract_name
,count(distinct rtrim(r.lis_req_id)) AS Volume
,a.date_registered
-- Create Temp Table to contain daily data
FROM accession a
Left join xxxx P on a.xxxx_id = p.xxxx_id
Left join requester R on a.requester_id = r.requester_id
where
(([date_registered] >= @ReportDate and [date_registered] < dateadd(month,1,@ReportDate))
OR ([date_registered] >= dateadd(month,-12,@ReportDate) and [date_registered] < dateadd(month,-11,@ReportDate)))
-- Limit results to L1
AND a.lis_code = 'L'
-- Limit results to Visitype = I or E
AND visit_type IN('I', 'E')
GROUP BY
CONCAT('L1-',a.contract_code)
,a.date_registered
INSERT into #DailyVolumes(contract_name, Volume, date_registered)
SELECT
CONCAT('L2-',a.contract_code) AS contract_code
,count(distinct(CONCAT(rtrim(p.lis_xxxx_id), '-', rtrim(r.lis_req_id)))) AS Volume
,a.date_registered
FROM accession a
Left join xxxx P on a.xxxx_id = p.xxxx_id
Left join requester R on a.requester_id = r.requester_id
where
(([date_registered] >= @ReportDate and [date_registered] < dateadd(month,1,@ReportDate))
OR ([date_registered] >= dateadd(month,-12,@ReportDate) and [date_registered] < dateadd(month,-11,@ReportDate)))
-- Limit results to L2
AND a.lis_code = 'S'
-- Limit results to Visitype NOT I or E
AND visit_type NOT IN('I', 'E')
GROUP BY
CONCAT('L2-',a.contract_code)
,a.date_registered
INSERT into #DailyVolumes(contract_name, Volume, date_registered)
SELECT
CONCAT('L2-',a.contract_code) AS contract_code
,count(distinct rtrim(r.lis_req_id)) AS Volume
,a.date_registered
FROM accession a
Left join xxxx P on a.xxxx_id = p.xxxx_id
Left join requester R on a.requester_id = r.requester_id
where
(([date_registered] >= @ReportDate and [date_registered] < dateadd(month,1,@ReportDate))
OR ([date_registered] >= dateadd(month,-12,@ReportDate) and [date_registered] < dateadd(month,-11,@ReportDate)))
-- Limit results to L2
AND a.lis_code = 'S'
-- Limit results to Visitype = I or E
AND visit_type IN('I', 'E')
GROUP BY
CONCAT('L2-',a.contract_code)
,a.date_registered
-- SUM Daily Data into Monthly Slices
Select
sum(Volume) AS Volume
,contract_name
,DATEADD(MONTH, DATEDIFF(MONTH, 0, date_registered), 0) AS MonthRegistered
FROM #DailyVolumes
group by
contract_name
,DATEADD(MONTH, DATEDIFF(MONTH, 0, date_registered), 0)
ORDER BY MonthRegistered DESC
-- Clear Temp Table
DROP TABLE #DailyVolumes
此结果集在SSMS中返回大约需要25秒。
我DID尝试运行我的查询8次而不是4次 - 对于上面的每个日期条款一次,并且有时间将结果集返回到大约6秒 - 这是一个非常好的结果,但对我来说似乎是反直觉的。 .. 编辑: - 服务器必须缓存结果。在我独自离开一个小时后 - 我得到了一些我期待的结果 - 跑了大概48秒。因此,拆分OR子句并再次运行4个查询中的每一个=没有净增益。
我想知道是否有更高效的SQL可以更快地返回结果集。我认为给服务器这样的OR声明会带来很大的开销,但我不确定在单个选择中运行它的更好方法。
编辑:date_registered IS INDEXED
答案 0 :(得分:0)
也许我的眼睛需要测试,但我实际上并不明白你为什么要进行4次查询。但是假设我的眼睛欺骗了我,你可以使用这样的python3.5 testfilter.py /etc/blacklist.lst update -p 22 -v yes
:
common table expression
答案 1 :(得分:0)
如果a.list_code = 'L'
显示文字&#39; L1 - &#39;则会显示,否则如果a.list_code = 'S'
则需要文字&#39; L2 - &#39;。为此,我使用了一个案例陈述。
如上所述,您需要where visit_type IN ('I', 'E')
和where visit_type not in ('I', 'E')
两个a.list_code IN ('L', 'S')
。由于两者都进入相同的临时表,因此我删除了针对过滤器('I', 'E')
的多个查询。所以现在只有1个带有过滤器WHERE a.lis_code IN ('L', 'S')
的查询。我希望这是正确的......没有任何测试数据,所以我无法验证。
ltrims和rtrims总是减慢查询...看看你是否可以删除它们。
这是我的尝试:
Declare @ReportDate DateTime
SET @ReportDate = dateadd(month,-1,DATEADD(month, DATEDIFF(month, 0, sysdatetime()), 0))
CREATE TABLE #DailyVolumes
(contract_name VARCHAR(50),
Volume INT,
date_registered DATETIME
);
INSERT into #DailyVolumes(contract_name, Volume, date_registered)
SELECT
CASE WHEN a.lis_code = 'L'
THEN 'L1-'
ELSE 'L2-'
END + a.contract_code AS contract_name
,count(distinct(CONCAT(rtrim(p.lis_xxxx_id), '-', rtrim(r.lis_req_id)))) AS Volume
,a.date_registered
-- Create Temp Table to contain daily data
FROM accession a
Left join xxxx P on a.xxxx_id = p.xxxx_id
Left join requester R on a.requester_id = r.requester_id
where
( ([date_registered] >= @ReportDate and [date_registered] < dateadd(month,1,@ReportDate))
OR ([date_registered] >= dateadd(month,-12,@ReportDate) and [date_registered] < dateadd(month,-11,@ReportDate))
)
AND a.lis_code IN ('L', 'S')
GROUP BY
CASE WHEN a.lis_code = 'L'
THEN 'L1-'
ELSE 'L2-'
END + a.contract_code
,a.date_registered
-- SUM Daily Data into Monthly Slices
Select
sum(Volume) AS Volume
,contract_name
,DATEADD(MONTH, DATEDIFF(MONTH, 0, date_registered), 0) AS MonthRegistered
FROM #DailyVolumes
group by
contract_name
,DATEADD(MONTH, DATEDIFF(MONTH, 0, date_registered), 0)
ORDER BY MonthRegistered DESC
-- Clear Temp Table
DROP TABLE #DailyVolumes