我有一种相当复杂(且非常低效)的方式从大量期间获得利用率(下面的代码)。
目前我正在运行这个为期8周的时间,并且需要30到40秒才能返回数据。
我需要定期运行6个月,1年和2年,这显然需要花费大量时间。
是否有更智能的方法来运行此查询以降低表扫描的数量? 我尝试了几种加入数据的方法,似乎都返回了垃圾数据。
我尽可能多地评论代码,但如果有什么不清楚请告诉我。
表大小:
[Stock] ~12,000 records
[Contitems] ~90,000 records
为了清晰起见,伪代码:
For each week between Start and End:
Get list of unique items active between dates (~12,000 rows)
For each unique item
Loop through ContItems table (~90,000 rows)
Return matches
Group
Group
Return results
守则
DECLARE @WEEKSTART DATETIME; -- Used to pass start of period to search
DECLARE @WEEKEND DATETIME; -- Used to pass end of period to search
DECLARE @DC DATETIME; -- Used to increment dates
DECLARE @INT INT; -- days to increment for each iteration (7 = weeks)
DECLARE @TBL TABLE(DT DATETIME, SG VARCHAR(20), SN VARCHAR(50), TT INT, US INT); -- Return table
SET @WEEKSTART = '2012-05-01'; -- Set start of period
SET @WEEKEND = '2012-06-25'; -- Set end of period
SET @DC = @WEEKSTART; -- Start counter at first date
SET @INT = 7; -- Set increment to weeks
WHILE (@DC < @WEEKEND) -- Loop through dates every [@INT] days (weeks)
BEGIN
SET @DC = DATEADD(D,@INT,@DC); -- Add 7 days to the counter
INSERT INTO @TBL (DT, SG, SN, TT, US) -- Insert results from subquery into return table
SELECT @DC, SUB.GRPCODE, SubGrp.NAME, SUM(SUB.TOTSTK), SUM(USED)
FROM
(
SELECT STK.GRPCODE, 1 AS TOTSTK, CASE (SELECT COUNT(*)
FROM ContItems -- Contains list of hires with a start and end date
WHERE STK.ITEMNO = ContItems.ITEMNO -- unique item reference
AND ContItems.DELDATE <= DATEADD(MS,-2,DATEADD(D,@INT,@DC)) -- Hires starting before end of week searching
AND (ContItems.DOCDATE#5 >= @DC -- Hires ending after start of week searching
OR ContItems.DOCDATE#5 = '1899-12-30 00:00:00.000')) -- Or hire is still active
WHEN 0 THEN 0 -- None found return zero
WHEN NULL THEN 0 -- NULL return zero
ELSE 1 END AS USED -- Otherwise return 1
FROM Stock STK - List of unique items
WHERE [UNIQUE] = 1 AND [TYPE] != 4 -- Business rules
AND DATEPURCH < @DC AND (DATESOLD = '1899-12-30 00:00:00.000' OR DATESOLD > DATEADD(MS,-2,DATEADD(D,@INT,@DC))) -- Stock is valid between selected week
) SUB
INNER JOIN SubGrp -- Used to get 'pretty' names
ON SUB.GRPCODE = SubGrp.CODE
GROUP BY SUB.GRPCODE, SubGrp.NAME
END
-- Next section gets data from temp table
SELECT SG, SN, SUM(TT) AS TOT, SUM(US) AS USED, CAST(SUM(US) AS FLOAT) / CAST(SUM(TT) AS FLOAT) AS UTIL
FROM @TBL
GROUP BY SG, SN
ORDER BY TOT DESC
答案 0 :(得分:2)
我有两个建议。
首先,重写查询以将“select”语句从case语句移动到from子句:
SELECT @DC, SUB.GRPCODE, SubGrp.NAME, SUM(SUB.TOTSTK), SUM(USED)
FROM (SELECT STK.GRPCODE, 1 AS TOTSTK,
(CASE MAX(Contgrp.cnt) -- Or hire is still active
WHEN 0 THEN 0 -- None found return zero
WHEN NULL THEN 0 -- NULL return zero
ELSE 1
END) AS USED -- Otherwise return 1
FROM Stock STK left outer join -- List of unique items
(SELECT itemno, COUNT(*) as cnt
FROM ContItems -- Contains list of hires with a start and end date
WHERE ContItems.DELDATE <= DATEADD(MS,-2,DATEADD(D,@INT,@DC)) AND -- Hires starting before end of week searching
(ContItems.DOCDATE#5 >= @DC OR -- Hires ending after start of week searching
ContItems.DOCDATE#5 = '1899-12-30 00:00:00.000'
)
group by ITEMNO
) ContGrp
on STK.ITEMNO = ContItems.ITEMNO
WHERE [UNIQUE] = 1 AND [TYPE] != 4 AND -- Business rules
DATEPURCH < @DC AND (DATESOLD = '1899-12-30 00:00:00.000' OR DATESOLD > DATEADD(MS,-2,DATEADD(D,@INT,@DC))) -- Stock is valid between selected week
) SUB INNER JOIN SubGrp -- Used to get 'pretty' names
ON SUB.GRPCODE = SubGrp.CODE
GROUP BY SUB.GRPCODE, SubGrp.NAME
在这样做的过程中,我发现了一些可疑的东西。 case语句在“ItemNo”级别运行,但分组是“GrpCode”。因此,“Count(*)”实际上是在组级返回总和。这是你想要的吗?
如果你有多个星期,第二个是免除WHILE循环。要做到这一点,您只需要将DatePurch转换为适当的一周。但是,如果代码通常仅在一到两周内运行,那么这种努力可能无济于事。
答案 1 :(得分:1)
好吧,首先替换WHERE子句中的DATEADD函数。
你已经拥有
SET @DC = DATEADD(D,@INT,@DC);
为什么不为删除日期声明另一个局部变量:
WHILE (@DC < @WEEKEND) -- Loop through dates every [@INT] days (weeks)
BEGIN
SET @DC = DATEADD(D,@INT,@DC);
DECLARE @DeletionDate DATETIME = DATEADD(MS,-2,DATEADD(D,@INT,@DC));
并在案例陈述中使用它:
CASE (SELECT COUNT(*) .... AND ContItems.DELDATE <= @DeletionDate ....
并且在外部where子句......
然后,您需要确保已正确索引表格。