代码之家  ›  专栏  ›  技术社区  ›  user366312

SQL连接需要很长时间

  •  1
  • user366312  · 技术社区  · 16 年前

    我有两张桌子

    (1) MonthlyTarget {SalesManCode, TargetMonthYear, TargetValue}; 这张桌子有1966177行。

    (2) MonthlySales  {SalesManCode, SaleDate, AchievedValue};
    

    这张桌子有400310行。

    我必须进行一个查询,生成如下表所示的结果:

    {SalesManCode, JanTar, JanAch, FebTar, FebAch,....., DecTar, DecAch}
    

    问题是,连接这两个表需要很长时间。

    查询应该是什么?

    如何优化查询?

    我不想考虑索引。

    7 回复  |  直到 7 年前
        1
  •  3
  •   marc_s    7 年前

    看起来您的monthlyTarget表中缺少一些列,即“targetDate”列。

    除了每个人都已经说过的索引之外,有时候分而治之的方法真的会有帮助。与其将1966177行表连接到400310行表中,不如创建一个小的临时表,然后将它们连接在一起:

    CREATE TABLE #MonthlySalesAgg
    (
        SalesManCode int,
        JanTar money,
        FebTar money,
        MarTar money,
        AprTar money,
        MayTar money,
        JunTar money,
        JulTar money,
        AugTar money,
        SepTar money,
        OctTar money,
        NovTar money,
        DecTar money
    
        PRIMARY KEY CLUSTERED (SalesManCode)
    )
    
    INSERT INTO #MonthlySalesAgg
    SELECT *
    FROM
    (SELECT SalesManCode, TargetValue, SaleMonth = Month(TargetDate) FROM MonthlyTarget) as temp
    PIVOT
    (
        Max(TargetValue)
        FOR [SaleMonth] IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
    ) as p
    
    CREATE TABLE #MonthlyTargetAgg
    (
        SalesManCode int,
        JanAch money,
        FebAch money,
        MarAch money,
        AprAch money,
        MayAch money,
        JunAch money,
        JulAch money,
        AugAch money,
        SepAch money,
        OctAch money,
        NovAch money,
        DecAch money
    
        PRIMARY KEY CLUSTERED (SalesManCode)
    )
    
    INSERT INTO #MonthlyTargetAgg
    SELECT * FROM
    (SELECT SalesManCode, AchievedValue, SaleMonth = Month(SaleDate) FROM MonthlySales) as temp
    PIVOT
    (
        Sum(AchievedValue)
        FOR [SaleMonth] IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
    ) as p
    

    上面的查询创建了两个中间表,中间表应包含与您的销售员表相同数量的记录。加入他们很简单:

    SELECT *
    FROM #MonthlyTargetAgg target
    INNER JOIN #MonthlySalesAgg sales ON target.SalesManCode = sales.SalesManCode
    

    如果您发现自己需要一直按月提取数据,请将代码移到视图中。

    Pivot需要SQL Server 2005或更高版本,它通常是一个非常有用的运算符。希望SQLServer2008允许用户一次在多个列上进行透视,这将导致比上面显示的查询更简单。

    使用SQL Server 2000:

    Pivot是语法Sugar。例如,

    SELECT * FROM
    (SELECT SalesManCode, AchievedValue, SaleMonth = Month(SaleDate) FROM MonthlySales) as temp
    PIVOT
    (
        Sum(AchievedValue)
        FOR [SaleMonth] IN ([1],[2],[3],[4],[5],[6],[7],[8],[9],[10],[11],[12])
    ) as p
    

    变成

    SELECT
        SalesManCode,
        [1] = Sum(case SaleMonth when 1 then AchievedValue else 0 end),
        [2] = Sum(case SaleMonth when 2 then AchievedValue else 0 end),
        [3] = Sum(case SaleMonth when 3 then AchievedValue else 0 end),
        [4] = Sum(case SaleMonth when 4 then AchievedValue else 0 end),
        [5] = Sum(case SaleMonth when 5 then AchievedValue else 0 end),
        [6] = Sum(case SaleMonth when 6 then AchievedValue else 0 end),
        [7] = Sum(case SaleMonth when 7 then AchievedValue else 0 end),
        [8] = Sum(case SaleMonth when 8 then AchievedValue else 0 end),
        [9] = Sum(case SaleMonth when 9 then AchievedValue else 0 end),
        [10] = Sum(case SaleMonth when 10 then AchievedValue else 0 end),
        [11] = Sum(case SaleMonth when 11 then AchievedValue else 0 end),
        [12] = Sum(case SaleMonth when 12 then AchievedValue else 0 end)
    FROM
        (SELECT SalesManCode, AchievedValue, SaleMonth = Month(SaleDate) FROM MonthlySales) as temp
    GROUP BY SalesManCode
    
        2
  •  4
  •   Lost in Alabama    16 年前

    好吧,如果您不想考虑索引,那么您将总是执行完整的表扫描,并且性能不会得到提高。

        3
  •  3
  •   Andrew Hare    16 年前

    检查表上的索引是否正确。几乎不可能不看数据库本身就说出来,但是99%的慢速连接时间是由于不正确或缺少表索引造成的。

        4
  •  1
  •   Donald Byrd    16 年前

    我不想考虑索引。

    你必须考虑索引。无论您如何编写查询,DB引擎都别无选择,只能扫描每个表以查找联接,它很可能会一次又一次地这样做。你别无选择。

    如果您不想因为无法控制数据库而混乱索引,请考虑将数据导出到本地SQL Express实例。

    甚至可以将数据导出到平面文件,通过Salesmancode对文件进行排序,并编写一个简单的程序来读取和匹配这些文件,都会更快。

        5
  •  1
  •   D'Arcy Rittich    16 年前

    如果不解雇一批销售人员,考虑以下选项:

    • 创建一个批处理进程以在夜间运行,并用查询的输出填充一些报表表。
    • 创建所需查询的索引/物化视图(尽管您需要在索引视图上创建索引,因此这可能会打破无索引规则)
        6
  •  0
  •   Jay Mooney    16 年前

    你有过滤器吗?您可以将一些部分结果存储在临时表中,然后在减小数据大小后连接到其余数据吗?

        7
  •  0
  •   Justin Balvanz    16 年前

    如果索引不是一个选项,唯一加快速度的方法就是把它放在一个更快的服务器上。不过,有件事告诉我索引会更容易。