SQL加入需要很长时间

时间:2009-06-23 13:31:48

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

我有两张桌子

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

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

此表有400310行。

我必须创建一个产生类似下表的结果的查询:

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

问题是,加入这两个表需要很长时间。

查询应该是什么?

如何优化查询?

我不想考虑索引。

7 个答案:

答案 0 :(得分:4)

好吧,如果您不想考虑索引,那么您将始终执行全表扫描并且性能不会得到改善。

答案 1 :(得分:3)

检查表格的正确索引。如果不查看数据库本身几乎是不可能的,但99%的时间缓慢连接是由于表索引不正确或丢失。

答案 2 :(得分:3)

看起来你在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

答案 3 :(得分:1)

  

我不想考虑索引。

您必须考虑建立索引。无论你如何编写查询,db引擎别无选择,只能扫描每个表寻找连接,它可能会一遍又一遍地执行。你别无选择。

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

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

答案 4 :(得分:1)

如果没有解雇一大批销售人员,请考虑以下选项:

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

答案 5 :(得分:0)

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

答案 6 :(得分:0)

如果索引不是一个选项,那么加速它的另一种方法是将它放在速度更快的服务器上。有些东西告诉我索引会更容易。