Tsql 比较日期的查询运行缓慢
谁能给点建议吗。下面的查询使用了大约200000条记录。我需要评估“DateTime”字段,以评估收入是否发生在正确的时间段内。我目前正在使用CASE语句来计算DateTime字段,它是一个绝对的pig,运行时间超过5分钟。有没有更快更有效的方法?请注意,变量@cur_date、@end_date、@prev_yr_qtr_start、@cur_date_yr_prev等均为字符串,r.pw_ship_date为DATETIME类型。所以本质上我是在比较r.pw_ship_date和字符串,即“2017-01-01 00:00” 注意:当我为200000条记录添加“SELECT TOP(500)”时,运行此查询花费了4:00分钟,这将永远花费时间 提前谢谢Tsql 比较日期的查询运行缓慢,tsql,Tsql,谁能给点建议吗。下面的查询使用了大约200000条记录。我需要评估“DateTime”字段,以评估收入是否发生在正确的时间段内。我目前正在使用CASE语句来计算DateTime字段,它是一个绝对的pig,运行时间超过5分钟。有没有更快更有效的方法?请注意,变量@cur_date、@end_date、@prev_yr_qtr_start、@cur_date_yr_prev等均为字符串,r.pw_ship_date为DATETIME类型。所以本质上我是在比较r.pw_ship_date和字符串,即“
DECLARE @total TABLE
(
acct_number VARCHAR(50),
pro_nbr VARCHAR(50),
sales_rep VARCHAR(50),
bill_to_name VARCHAR(50),
billing_addr1 VARCHAR(50),
billing_addr2 VARCHAR(50),
billing_city CHAR(50),
billing_state CHAR(2),
billing_zip CHAR(10),
cur_month_bills INT,
cur_month_rev DECIMAL(30, 6),
cur_qtr_bills INT,
cur_qtr_rev DECIMAL(30, 6),
prev_yr_qtr_bills INT,
prev_yr_qtr_rev DECIMAL(30, 6),
cur_ytd_bills INT,
cur_ytd_rev DECIMAL(30, 6),
prev_ytd_bills INT
)
INSERT INTO @total
SELECT TOP(50000) f.acct_number ,
r.pro_nbr ,
r.sales_rep ,
r.bill_to_name ,
r.billing_addr1 ,
r.billing_addr2 ,
r.billing_city ,
r.billing_state ,
r.billing_zip ,
'cur_month_bills' = MAX(( CASE WHEN r.pw_ship_date BETWEEN @cur_date AND @end_date THEN 1 ELSE 0 END )) ,
'cur_month_rev' = MAX(ROUND(( CASE WHEN r.pw_ship_date BETWEEN @cur_date AND @end_date THEN f.tot_revenue ELSE 0 END ), 2)) ,
'cur_qtr_bills' = MAX((CASE WHEN r.pw_ship_date BETWEEN @cur_date AND @end_date THEN 1 ELSE 0 END )) ,
'cur_qtr_rev' = MAX(ROUND(CASE WHEN r.pw_ship_date BETWEEN @cur_date AND @end_date THEN f.tot_revenue ELSE 0 END, 2)) ,
'prev_yr_qtr_bills' = MAX(CASE WHEN r.pw_ship_date BETWEEN @prev_yr_qtr_start AND @cur_date_yr_prev THEN 1 ELSE 0 END ) ,
'prev_yr_qtr_rev' = MAX(ROUND(CASE WHEN r.pw_ship_date BETWEEN @prev_yr_qtr_start AND @cur_date_yr_prev THEN f.tot_revenue ELSE 0 END , 2)) ,
'cur_ytd_bills' = MAX(CASE WHEN r.pw_ship_date BETWEEN @first_day_cur_yr AND @end_date THEN 1 ELSE 0 END ),
'cur_ytd_rev' = MAX(ROUND(CASE WHEN r.pw_ship_date BETWEEN @first_day_cur_yr AND @end_date THEN f.tot_revenue ELSE 0 END , 2)) ,
'prev_ytd_bills' = MAX(CASE WHEN r.pw_ship_date BETWEEN @first_day_prev_yr AND @end_date THEN 1 ELSE 0 END )
FROM @summed f
INNER JOIN @raw r ON f.acct_number = r.acct_number AND f.pro_nbr = r.pro_nbr
GROUP BY f.acct_number ,
r.pro_nbr ,
r.sales_rep ,
r.bill_to_name ,
r.billing_addr1 ,
r.billing_addr2 ,
r.billing_city ,
r.billing_state ,
r.billing_zip;
将表变量
@raw
和@summared
更改为临时表。表变量没有统计信息,在索引方面非常有限(只能有一个)。因此,SQL Server假定您的表变量只有一行(2012及更早版本)或100行(2014+)。这意味着您几乎肯定会得到一个糟糕的查询执行计划,这会毁了您
一旦您将@raw
和@summated
更改为#raw
和#summated
,在它们上建立索引-至少为外键(您要加入的字段)、账号和pro nbr
建立索引。创建聚集索引和/或主键可能是值得的,但这是您需要进行试验才能找到所需性能的东西
另一个影响性能的因素是将datetime
s与字符串进行比较。这会导致类型转换,并且会严重拖累您。如果使用的是日期/时间,请使用适当的数据类型——而不是看起来像日期的字符串
如果这仍然不够快,请将CASE
语句移出聚合函数
MAX(如果r.pw\u ship\u日期介于@cur\u日期和@end\u日期之间,则为1或0 end))
将CASE
语句移动到填充#raw.pw_ship_date
的查询中,这样在执行聚合时,您只需一直查看整数。您应该将所有变量更改为DateTime
。(有关详细信息,请参阅。)您还可以添加一个where
子句,将处理的行范围限制为所需的最早和最晚日期,即@第一天\上一年
可能是最小值,@结束日期
可能是最大值。(我假设表中有超出该范围的数据。)提示:使用适当的软件(MySQL、Oracle、DB2等)和版本(例如sql-server-2014
)标记数据库问题是很有帮助的。请说明如何创建表变量@raw
和@summated
。