【问题标题】:SQL Join taking long timeSQL Join 需要很长时间
【发布时间】:2009-06-23 13:31:48
【问题描述】:

我有两张桌子

(1) MonthlyTarget {SalesManCode, TargetMonthYear, TargetValue}; 这个表有 1966177 行。

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

此表有 400310 行。

我必须进行查询,产生如下表的结果:

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

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

查询应该是什么?

如何优化查询?

我不想考虑编制索引。

【问题讨论】:

  • 您能否发布您当前的声明,也许我们可以看到您在做什么?
  • 为什么不想考虑索引?除非您不编制索引的理由非常充分,否则我会重新考虑,因为编制索引可能是提高性能的最佳方式。
  • "MonthlyTarget {SalesManCode, TargetValue};这张表有 1966177 行" - 销售员很多 ;)
  • 我认为像“我不想考虑索引”这样的陈述真的应该是合格的。 为什么你不想考虑索引?慢查询是正确的索引,因为感染是抗生素(在大多数情况下)。无缘无故地抛弃最可能是最好的解决方案对您或我们都没有帮助。

标签: sql sql-server tsql sql-server-2000


【解决方案1】:

好吧,如果您不想考虑建立索引,那么您将始终执行全表扫描,并且性能不会提高。

【讨论】:

    【解决方案2】:

    您的 MonthlyTarget 表中似乎缺少一些列,即“T​​argetDate”列。

    除了每个人已经说过的关于索引的内容之外,有时分而治之的方法确实会有所帮助。与其将 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
    

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

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

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

    PIVOT 需要 SQL Server 2005 或更高版本,它通常是一个非常有用的运算符。希望 SQL Server 2008 将允许用户一次以多个列为轴,这将产生比上面显示的更简单的查询。

    使用 SQL Server 2000:

    PIVOT 是语法糖。例如,

    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
    

    【讨论】:

    • 如何在 SQL Server 2000 中实现这一点?
    • 我已经更新了我的代码,将 PIVOT 转换为在 SQL Server 2000 中工作的东西。
    • +1 - 很好地解释了实现 PIVOT 操作和现实世界的相关性。做得很好。
    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

      我不想考虑编制索引。

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

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

      哎呀,即使将数据导出到平面文件,按 SalesManCode 对文件进行排序并编写一个简单的程序来读取和匹配它们也会更快。

      【讨论】:

        【解决方案5】:

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

        • 创建一个批处理以每晚运行并使用查询的输出填充一些报告表
        • 为您想要的查询创建一个索引/物化视图(尽管您需要在索引视图上创建一个索引,所以这可能会违反您的无索引规则)

        【讨论】:

          【解决方案6】:

          你有过滤器吗?您能否将部分结果存储在临时表中,然后在减少数据大小后加入其余数据?

          【讨论】:

            【解决方案7】:

            如果索引不是一个选项,那么加快它的唯一其他方法就是将它放在更快的服务器上。不过有些事情告诉我索引会更容易。

            【讨论】:

              猜你喜欢
              • 2016-02-02
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2016-09-29
              • 1970-01-01
              • 2015-10-05
              相关资源
              最近更新 更多