您好我在这里附加了我想在项目中使用的示例表结构
CREATE TABLE TESTSALESVOLUMETABLE
(
ID INT IDENTITY(1,1),
AMOUNT DECIMAL(18,2),
CREDITEDDATE DATETIME
)
以及我使用的查询
DECLARE @CURRENTDATE AS DATETIME = GETDATE()
DECLARE @PSV AS INT = 0
DECLARE @TOTAL AS INT = 0
IF (DATEPART(DAY, @CURRENTDATE) <= 15)
BEGIN
SELECT @PSV = (
SELECT Sum(AMOUNT)
FROM TESTSALESVOLUMETABLE
WHERE DATEPART(DAY, CREDITEDDATE) <= 15
AND MONTH(CREDITEDDATE) = MONTH(@CURRENTDATE)
AND YEAR(CREDITEDDATE) = YEAR(@CURRENTDATE)
)
END
ELSE
BEGIN
SELECT @PSV = (
SELECT Sum(AMOUNT)
FROM TESTSALESVOLUMETABLE
WHERE DATEPART(DAY, CREDITEDDATE) > 15
AND MONTH(CREDITEDDATE) = MONTH(@CURRENTDATE)
AND YEAR(CREDITEDDATE) = YEAR(@CURRENTDATE)
)
END
SELECT @total = (
SELECT Sum(Amount)
FROM TESTSALESVOLUMETABLE
)
SELECT @PSV 'PSV',
@total 'TOTAL'
有没有办法提高此查询的性能
答案 0 :(得分:2)
首先,您不需要子查询来设置变量。其次,在列上使用函数通常会阻止索引的使用。所以,我会推荐这样的东西:
SELECT @PSV = Sum(AMOUNT)
FROM TESTSALESVOLUMETABLE
WHERE CREDITEDDATE >= DATEADD(DAY, 1 - DAY(GETDATE()), CAST(GETDATE() as DATE)) AND
CREDITEDDATE < DATEADD(DAY, 16 - DAY(GETDATE()), CAST(GETDATE() as DATE));
然后,您需要TESTSALESVOLUMETABLE(CREDTEDDATE, AMOUNT)
上的索引。
答案 1 :(得分:1)
遵循以下指南:Bad habits to kick : mis-handling date / range queries - Aaron Bertrand - 2009-10-16
首先,我们要摆脱:
where datepart(day, crediteddate) <= 15
and month(crediteddate)=month(@currentdate)
and year(crediteddate)=year(@currentdate)
因为:
[...]您已经有效地消除了SQL Server利用索引的可能性。由于你强迫它建立一个不可行的条件,这意味着它必须转换表中的每一个值,以便将它与你在右边显示的[值]进行比较[...... ]
其次,我们希望确保避免将between
与日期时间一起使用,因为它可以返回不需要的行或错过所需的行,即使使用between ... and dateadd(second, -1, @thrudate)
甚至between ... and 'yyyy-mm-ddT23:59:59.997'
之类的内容也是如此。 (有关此问题的更多示例,请参阅Aaron Bertrand's article。)
所以最好的办法是:
如果今天是15日或更早,请获取行&gt; =本月1日和&lt;本月16日
如果今天是16日或更晚,请获取行&gt; =本月16日&lt;下个月1日
此外,正如Gordon Linoff所提到的,您将受益于testsalesvolumetable(crediteddate, amount)
上的索引。但戈登的公式总是会回到本月的第1和第16位。
我们可以计算日期和日期,只需使用一个查询,而不是根据当天将过程分为两个查询。
以下是使用和不使用from和thru日期变量的示例代码,以及用于检查结果范围的快速日历测试。
用于测试设置的rextester链接:http://rextester.com/YVLI65217
create table testsalesvolumetable (crediteddate datetime not null, amount int not null)
insert into testsalesvolumetable values
('20161201',1) ,('20161202',1) ,('20161203',1) ,('20161204',1) ,('20161205',1)
,('20161206',1) ,('20161207',1) ,('20161208',1) ,('20161209',1) ,('20161210',1)
,('20161211',1) ,('20161212',1) ,('20161213',1) ,('20161214',1) ,('20161215',1)
,('20161216',1) ,('20161217',1) ,('20161218',1) ,('20161219',1) ,('20161220',1)
,('20161221',1) ,('20161222',1) ,('20161223',1) ,('20161224',1) ,('20161225',1)
,('20161226',1) ,('20161227',1) ,('20161228',1) ,('20161229',1) ,('20161230',1)
,('20161231',1) ,('20170101',1)
/* ----- without variables */
declare @psv int;
select @psv = Sum(amount)
from testsalesvolumetable
where crediteddate >= dateadd(day, (1- (day(convert(date,getdate()))/16)) - (day(convert(date,getdate()))%16), convert(date,getdate()))
and crediteddate < case
when day(convert(date,getdate()))>15
then dateadd(month, datediff(month, -1, convert(date,getdate())), 0)
else dateadd(day,15,dateadd(month, datediff(month, 0, convert(date,getdate())), 0))
end;
select psv=@psv;
--*/
/* ----- with variables */
--declare @psv int;
declare @currentdate date;
/* change to date datatype to get rid of time portion*/
set @currentdate = getdate();
--set @currentdate = '20161212'
declare @fromdatetime datetime;
declare @thrudatetime datetime;
set @fromdatetime = dateadd(day, (1- (day(@currentdate)/16)) - (day(@currentdate)%16), @currentdate);
set @thrudatetime = case
when day(@currentdate)>15
then dateadd(month, datediff(month, -1, @currentdate), 0)
else dateadd(day,15,dateadd(month, datediff(month, 0, @currentdate), 0))
end;
select @psv = sum(amount)
from testsalesvolumetable
where crediteddate >= @fromdatetime
and crediteddate < @thrudatetime;
--/*
select
psv=@psv
, CurrentDate =convert(varchar(10),@currentdate ,121)
, FromDateTime=convert(varchar(10),@fromdatetime,121)
, ThruDateTime=convert(varchar(10),@thrudatetime,121);
--*/
日历测试的Rextester链接:http://rextester.com/ESZRH30262
--/* ----- Calendar Test */
;with n as (
select n from (values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10)) t(n)
)
, cal as (
select DateValue=convert(datetime,dateadd(day, row_number() over (order by (select 1)) -1, '20160101'))
from n as a
cross join n as b
cross join n as c
cross join n as d
)
select
--DateValue=convert(varchar(10),DateValue,121)
minDate =convert(varchar(10),min(DateValue),121)
, maxDate =convert(varchar(10),max(DateValue),121)
, FromDatetime=convert(varchar(10),dateadd(day, (1- (day(DateValue)/16)) - (day(DateValue)%16), DateValue),121)
, ThruDatetime=convert(varchar(10),case
when day(DateValue)>15
then dateadd(m, datediff(m, -1, DateValue), 0)
else convert(varchar(10),dateadd(day, 16 - day(DateValue), DateValue),121)
end,121)
, GordonFrom = convert(varchar(10),dateadd(day, 1 - day(DateValue), cast(DateValue as date)),121)
, GordonThru = convert(varchar(10),dateadd(day, 16 - day(DateValue), cast(DateValue as date)),121)
from cal
where datevalue >= '20160101'
and datevalue < '20170101'
--/*
group by
convert(varchar(10),dateadd(day, (1- (day(DateValue)/16)) - (day(DateValue)%16), DateValue),121)
, convert(varchar(10),case
when day(DateValue)>15
then dateadd(m, datediff(m, -1, DateValue), 0)
else convert(varchar(10),dateadd(day, 16 - day(DateValue), DateValue),121)
end,121)
, convert(varchar(10),dateadd(day, 1 - day(DateValue), cast(DateValue as date)),121)
, convert(varchar(10),dateadd(day, 16 - day(DateValue), cast(DateValue as date)),121)
order by FromDateTime
答案 2 :(得分:0)
我认为这样可以正常工作
DECLARE @PSV AS INT = 0
DECLARE @TOTAL AS INT = 0
IF (DATEPART(DAY,GETDATE()) <= 15)
BEGIN
SELECT @PSV = Sum(AMOUNT)
FROM TESTSALESVOLUMETABLE
WHERE CREDITEDDATE >= DATEADD(DAY, 1 - DAY(GETDATE()), CAST(GETDATE() as DATE)) AND
CREDITEDDATE < DATEADD(DAY, 16 - DAY(GETDATE()), CAST(GETDATE() as DATE));
END
ELSE
BEGIN
SELECT @PSV = Sum(AMOUNT)
FROM TESTSALESVOLUMETABLE
WHERE CREDITEDDATE >= DATEADD(DAY, 16 - DAY(GETDATE()), CAST(GETDATE() as DATE)) AND
CREDITEDDATE < DATEADD(DAY, 31 - DAY(GETDATE()), CAST(GETDATE() as DATE));
END
SELECT @total = (
SELECT Sum(Amount)
FROM TESTSALESVOLUMETABLE
)
SELECT @PSV 'PSV',
@total 'TOTAL'