【问题标题】:Getting SQL server to apply where clause with cross join to query in a view让 SQL 服务器应用带有交叉连接的 where 子句在视图中进行查询
【发布时间】:2015-09-03 21:50:20
【问题描述】:

我在 stackoverflow 上的第一篇文章(随着时间的推移对我有很大帮助):

我有一个带有交叉连接的查询,当我使用 where 子句运行它时它工作正常,但当我将它放在视图中并应用 where 视图的子句。

我认为问题在于,当代码封装在视图中时,SQL 没有将 where 子句应用于交叉连接,因此最终有数百万行(而不是这里的 180案例)。

代码如下 - 它是一个查询,它使用平均预期每月使用量和传入订单列表来预测仓库中物品的未来现有库存。

CREATE VIEW [dbo].[ItemWarehouseStockForecastDaily2]
AS    
SELECT
    fd.AsafterDate
    , iw.idItem
    , iw.idWarehouse
    , iw.OnHandQuantity  
        + SUM(ISNULL(iwio.PurchaseOrderInboundQuantity, 0)
                - iws.AverageMonthlyDemandQuantity / (365.25/12)
            ) OVER (ORDER BY fd.AsafterDate) AS OnHandQuantity
FROM
    (
        ( SELECT CalendarDate Asafterdate 
          FROM Calendar c 
          WHERE c.CalendarDate > GETDATE() 
            AND c.CalendarDate < DATEADD(d, 180, GETDATE())
        ) fd -- This table has 180 rows
        -- This table has 10 million rows - one per item per warehouse
        CROSS JOIN ItemWarehouse iw 
    )
    LEFT JOIN ItemWarehouseDemandFromStockStatisticsMonthly iws
           ON iws.idItem = iw.idItem 
          AND iws.idWarehouse = iw.idWarehouse
    LEFT JOIN ItemWarehouseInboundAndOutboundQuantitiesWithDueDate iwio 
           ON iwio.idItem = iw.idItem 
          AND iwio.idWarehouse = iw.idWarehouse 
          AND iwio.DueDate = fd.Asafterdate
/*
WHERE iw.idItem = 12345
  AND iw.idWarehouse = 67
ORDER BY AsafterDate
*/

注释掉的 where 子句使查询在不在视图中时(按 idwarehouse、iditem 聚类的表)快速运行(亚秒级)

我们将不胜感激任何/所有帮助和建议。

【问题讨论】:

  • itemWarehouse 作为查询中的基表是否有意义?
  • 如果我不得不猜测,这是一个执行计划问题。您是否尝试将 OPTION (RECOMPILE) 添加到您的选择语句中?
  • 我并不是说这是一个答案,但如果你使用表格函数而不是视图,如果你能告诉我结果,我是居里夫人!即将所有视图代码放入一个表函数并运行相同的测试。速度和视图一样吗?我发现表函数在这类事情上会好很多。
  • 嗨 Stephan,你是对的 - 这绝对是一个执行计划问题 - 服务器没有将 where 子句与交叉连接相关联,因此该部分返回 4.6 亿行而不是 180 行然后服务器必须使用 where 子句过滤回 180。我就是找不到告诉服务器的方法!
  • 嗨@Paul,感谢您的建议。只要我将 idItemidWarehouse 作为参数传递,表函数值就可以很好地工作。当我只使用 where 子句时,我又迷路了。不幸的是,在使用 union 结合历史库存水平数据后,我暂时通过 MS Access 表单发布结果,因此查看会非常方便..

标签: sql-server tsql sql-server-2014


【解决方案1】:

我还没有评论的声誉。但是,在 technet 上检查它说,如果添加 where 语句(至少对于 SQL 2008 R2),交叉连接的行为应该与内部连接相同。 https://technet.microsoft.com/en-us/library/ms190690(v=sql.105).aspx

如果您使用内部联接,您是否检查过是否会出现同样的问题?

作为另一种选择,您可以将约束直接添加到 where 子句中吗?

CREATE VIEW [dbo].[ItemWarehouseStockForecastDaily2]
AS    
SELECT
fd.AsafterDate
, iw.idItem
, iw.idWarehouse
, iw.OnHandQuantity  
    + SUM(ISNULL(iwio.PurchaseOrderInboundQuantity, 0)
            - iws.AverageMonthlyDemandQuantity / (365.25/12)
        ) OVER (ORDER BY fd.AsafterDate) AS OnHandQuantity
FROM
(
    ( SELECT CalendarDate Asafterdate 
      FROM Calendar c 
      WHERE c.CalendarDate > GETDATE() 
        AND c.CalendarDate < DATEADD(d, 180, GETDATE())
    ) fd -- This table has 180 rows
    -- Filter right here instead of later:
    INNER JOIN ItemWarehouse iw ON iw.idItem = 12345 AND iw.idWarehouse = 67
)
LEFT JOIN ItemWarehouseDemandFromStockStatisticsMonthly iws
       ON iws.idItem = iw.idItem 
      AND iws.idWarehouse = iw.idWarehouse
LEFT JOIN ItemWarehouseInboundAndOutboundQuantitiesWithDueDate iwio 
       ON iwio.idItem = iw.idItem 
      AND iwio.idWarehouse = iw.idWarehouse 
      AND iwio.DueDate = fd.Asafterdate

【讨论】:

  • 早上@Arnek 谢谢你的回复!只要内部连接和 where 子句都包含在查询本身中,它们就可以工作。当我尝试将查询放入视图时出现问题,以便用户稍后在查看任意仓库中的任意项目时可以添加 where 子句(或联接)。在这种情况下,SQL Server 2014 不会将交叉连接过滤到 180 行,而是在过滤之前扩展整个交叉连接。现在我已经通过使用存储过程来解决它,该存储过程插入到特定 idItem/idWarehouse 的表中。
猜你喜欢
  • 2016-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-24
  • 2023-04-01
  • 1970-01-01
  • 2021-12-12
相关资源
最近更新 更多