有人可以提供一些建议。我有以下查询使用大约200,000条记录。我需要评估一个' DateTime'字段,用于评估收入是否在正确的时间段内发生。我目前正在使用CASE语句来评估DateTime字段,它是一个绝对的猪,它运行超过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'
注意:当我添加' SELECT TOP(500)'时,需要4:00分钟才能运行此查询。对于200,000条记录,这将永远需要。
提前致谢
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;
答案 0 :(得分:0)
将表变量@raw
和@summed
更改为临时表。表变量没有统计信息,并且在索引方面极其受限(您只能有一个)。因此,SQL Server假定您的表变量只有一行(2012年及以前)或100行(2014年以上)。这意味着你几乎肯定会为你的查询得到一个糟糕的执行计划,这会毁了你。
将@raw
和@summed
更改为#raw
和#summed
后,请在其上添加索引 - 至少为您的外键编制索引(您加入的字段,acct_number
和pro-nbr
。它可能值得创建聚集索引和/或主键,但这是您需要尝试以找到所需性能的东西。
另一件让你的表现失败的事情就是将datetime
与字符串进行比较。这导致类型转换,可能会显着拖累你。如果您正在使用日期/时间,使用适当的数据类型 - 而不是看起来像日期的字符串。
如果仍然没有足够快地运行,请将CASE
语句移出集合函数。
MAX(( CASE WHEN r.pw_ship_date BETWEEN @cur_date AND @end_date THEN 1 ELSE 0 END ))
将CASE
语句移动到填充#raw.pw_ship_date
的查询中,这样当您执行聚合时,您只需要一直查看整数。