Sql 计算利用率的更好方法

Sql 计算利用率的更好方法,sql,sql-server,sql-server-2008,tsql,Sql,Sql Server,Sql Server 2008,Tsql,我有一个相当复杂和非常低效的方法来从下面的大量代码中获取利用率 目前,我运行这个程序的时间为8周,返回数据需要30到40秒 我需要在6个月、1年和2年的时间内定期运行此功能,这显然需要大量的时间 是否有更智能的方法来运行此查询以减少表扫描的数量? 我尝试了几种连接数据的方法,所有这些方法似乎都返回垃圾数据 我试着尽可能多地注释代码,但如果有任何不清楚的地方,请告诉我 表格大小: [Stock] ~12,000 records [Contitems] ~90,000 recor

我有一个相当复杂和非常低效的方法来从下面的大量代码中获取利用率

目前,我运行这个程序的时间为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
代码


首先,替换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子句中


然后,您需要确保已正确地为表编制索引。

首先,替换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子句中


然后,您需要确保已正确索引表。

我有两个建议

首先,重写查询以将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转换为适当的周。但是,如果代码通常只运行一到两周,那么这项工作可能没有多大帮助。

我有两个建议

首先,重写查询以将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-这在查询中减少了一小部分,但仍然需要很长时间。在所有日期字段和唯一项目代码上设置索引。如果您的日期仅为以前的日期,则可以从表示Julian日期的整数列中获得更好的性能;或者,根据您查询这些数据的程度,如果您的日期仅为有史以来的日期,您可能会从表示Julian date的整数列中获得更好的性能;或者,根据您对这些数据的查询程度,进行完整的查询可能会有回报