是否有更快的方式来查询相隔12个月的2个月数据?

时间:2017-11-20 22:15:17

标签: sql-server datetime

我每月有大约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

2 个答案:

答案 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