【问题标题】:Performance Comparison: Full outer join vs Union, Union All性能比较:全外连接 vs Union、Union All
【发布时间】:2011-06-17 07:34:30
【问题描述】:

我有名为:

mktActualsales (SaleID, EmployeeID, PeriodID,PositionID)
 mktActualSalesItems(SaleItemID, saleID, Item, Quantity)
 mktSalesTargets(TargetID, EmployeeID, PeriodID,PositionID)
 mktSalesTargetItems(TargetITemID, TargetID,ItemID, Quantity )
 sysPeriods(PeriodID, StartDate, EndDate) 

上面的表sale和salesDetails之间的关系很明显,通过SaleID关联,Target和TargetDetail通过TargetID关联。我要显示的是员工在所有时期的销售额和目标。有些时期缺少销售,而在其他时期可能缺少目标。

我的计划(到目前为止)是在一个子查询中采用 sale 和 saleDetail 的内部联接,在另一个子查询中采用 target 和 targetDetail ,然后对两个子查询进行完全外部联接,从而获得我需要的数据。但结果非常缓慢。我可以做些什么来加快性能。我在谷歌上搜索了完全外部连接和联合之间的性能比较,但没有任何运气。目前我不知道使用 Union/Union All 是否可以达到我想要的结果。

编辑

这是我到目前为止的查询。也编辑了表格

SELECT  sale.ActualSaleID, 
        COALESCE (sale.EmployeeID, saleTarget.EmployeeID) AS EmployeeID, 
        COALESCE (sale.PositionID, saleTarget.PositionID) AS PositionID, 
        COALESCE (sale.PeriodID, saleTarget.PeriodID) AS PeriodID, 
        COALESCE (sale.SKUID, saleTarget.SKUID) AS SKUID, 
        COALESCE (sale.SalesQuantity, 0) AS SalesQuantity, 
        saleTarget.SalesTargetID, 
        COALESCE (saleTarget.TargetQuantity, 0) AS TargetQuantity, 
        saleTarget.SalesTargetItemID, 
        sale.ActualSaleItemID, 
        p.StartDate, 
        p.EndDate
FROM (
        SELECT  s.ActualSaleID, 
                s.EmployeeID, 
                s.PeriodID, 
                s.PositionID, 
                si.ActualSaleItemID, 
                si.SKUID, 
                si.SalesQuantity
        FROM dbo.mktActualSaleItems AS si 
            INNER JOIN dbo.mktActualSales AS s 
                ON si.ActualSaleID = s.ActualSaleID
    ) AS sale 
    FULL OUTER JOIN
    (
        SELECT  t.EmployeeID, 
                t.PeriodID, 
                t.PositionID, 
                t.SalesTargetID, 
                ti.SKUID, 
                ti.TargetQuantity, 
                ti.SalesTargetItemID
        FROM dbo.mktSalesTargetItems AS ti 
            INNER JOIN dbo.mktSalesTargets AS t 
                ON t.SalesTargetID = ti.SalesTargetID
    ) AS saleTarget 
        ON sale.PeriodID = saleTarget.PeriodID 
        AND sale.PositionID = saleTarget.PositionID 
        AND sale.SKUID = saleTarget.SKUID 
    INNER JOIN dbo.sysPeriods AS p 
        ON p.PeriodID = COALESCE (sale.PeriodID, saleTarget.PeriodID)

【问题讨论】:

  • 两个子查询都在 PeriodID 和 EmployeeID 上外连接
  • 您能否向我们提供您目前的查询以及您想要实现的一些示例?我不完全理解你想要的结果。
  • @Oliver Hanappi 编辑了问题

标签: sql sql-server-2008 union full-outer-join


【解决方案1】:

我认为您在查询中有一个错误 - 您在 SALE 和 SALETARGET 之间的连接不包括employeeID 列。 COALESCE 隐藏了这一点,但我认为你得到的行数远远超过你需要的......

但是,加快查询速度的方法是首先找出查询速度慢的原因;执行计划是要走的路。使用查询分析器告诉您发生了什么 - 您是否为所有连接点击索引?如果您已用尽当前实现的所有选项,则仅重写查询以使用联合语句。

就风格而言,我认为没有必要在您加入的列上使用 COALESCE - 首先它们永远不能为空,而且它往往会隐藏错误。

【讨论】:

  • EmployeeID 与 designationID 具有一对一的关系,我在这里只有一点非规范化,它不会给出不正确的结果。由于我采用完全外连接,因此一个表中的列很有可能为空
  • 我在查询中根本看不到 designationID - 您在 period、position 和 skuid 列上加入了 SALE 和 SALETARGET。因此,您将获得一个交叉联接——sales 和 saletarget 中的每个员工都有一个记录。这不正确吗?您可以尝试运行返回 sale.EmployeeID 和 saleTarget.EmployeeID 的查询来检查吗?
  • 啊 - 所以 PositionID 也是员工的唯一标识符?我假设它链接到一个带有职称或类似职位的表格——“销售经理”、“客户服务代表”。你看过查询计划吗?
  • 是的,正是为了避免再次加入
【解决方案2】:

我认为你不需要子查询,你可以在一个查询中做同样的事情

SELECT  s.ActualSaleID, 
        COALESCE (s.EmployeeID, t.EmployeeID) AS EmployeeID, 
        COALESCE (s.PositionID, t.PositionID) AS PositionID, 
        COALESCE (s.PeriodID, t.PeriodID) AS PeriodID, 
        COALESCE (si.SKUID, ti.SKUID) AS SKUID, 
        COALESCE (si.Quantity, 0) AS SalesQuantity, 
        t.TargetID, 
        COALESCE (ti.Quantity, 0) AS TargetQuantity, 
        ti.TargetITemID, 
        si.SaleItemID, 
        p.StartDate, 
        p.EndDate
FROM dbo.mktActualSales AS s 
        INNER JOIN dbo.mktActualSaleItems AS si 
            ON si.ActualSaleID = s.ActualSaleID
    FULL OUTER JOIN dbo.mktSalesTargets AS t 
        ON s.PeriodID = t.PeriodID 
        AND s.PositionID = t.PositionID 
        AND si.SKUID = ti.SKUID 
            INNER JOIN dbo.mktSalesTargetItems AS ti 
                ON t.SalesTargetID = ti.SalesTargetID
    INNER JOIN dbo.sysPeriods AS p 
        ON p.PeriodID = COALESCE (s.PeriodID, t.PeriodID)

我不确定如何命名字段,但你明白了。

这可能会加快查询速度。

别忘了检查索引!!

【讨论】:

  • 将它们放在子查询中只是让我更容易理解。没有子查询会提高性能吗?
  • 嗯,这取决于,您的 dbms 可能足够聪明,可以对您的查询进行适当的连接,但可能不是。您不让他有机会通过给他子查询来选择最佳计划,而在一个查询中,您让 dbms 选择最佳计划。最好的方法是运行查询...或者查看执行计划!
  • PeriodID 和 PositionID 存在于 mktActualSales 和 mktSalesTargets 中,而 SKUID 存在于 mktSaleTargetItems 和 mktAcutalSaleItems 中。你能相应地更新这个查询吗
猜你喜欢
  • 2012-09-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-07
相关资源
最近更新 更多