我有以下View,名为ViewGoods:
SELECT
G.Gid,
SI.[$Id] AS FirstSiteInId,
SI.Date AS FirstSiteInDate,
SI.Comments AS FirstSiteInComments,
S.[$Id] AS FirstSiteId,
S.[$Refex] AS FirstSiteRefex,
SI.Client AS ClientId,
C.[$Refex] AS ClientRefex,
CASE WHEN SI.Contract IS NULL THEN (SELECT Contract.[$Id]
FROM StockType AS ST
INNER JOIN StockTypeContract AS STC ON ST.[$Id] = STC.[$ParentId]
INNER JOIN Contract ON STC.Contract = Contract.[$Id]
WHERE ST.[$Id] = VGST.StockType
AND SI.Date >= STC.StartDate)
ELSE SI.Contract END AS Contract,
CASE WHEN SI.Contract IS NULL THEN (SELECT Contract.[$Refex]
FROM StockType AS ST
INNER JOIN StockTypeContract AS STC ON ST.[$Id] = STC.[$ParentId]
INNER JOIN Contract ON STC.Contract = Contract.[$Id]
WHERE ST.[$Id] = VGST.StockType
AND SI.Date >= STC.StartDate)
ELSE CT.[$Refex] END AS ContractRefex,
CASE WHEN COALESCE (Q.Quantity, 0) > 0 THEN L.SiteId ELSE NULL END AS SiteId,
CASE WHEN COALESCE (Q.Quantity, 0) > 0 THEN L.SiteRefex ELSE NULL END AS SiteRefex,
CASE WHEN COALESCE (Q.Quantity, 0) > 0 THEN L.Lid ELSE NULL END AS Lid,
ISNULL(W.Weight, VGSA.Weight * Q.Quantity) AS Weight,
COALESCE (Q.Quantity, 0) AS Quantity,
VGSA.Article,
VGSA.ArticleName,
VGST.StockType,
VGST.StockTypeRefex
FROM dbo.Goods AS G
INNER JOIN dbo.SiteIn AS SI ON G.SiteIn = SI.[$Id]
INNER JOIN dbo.Client AS C ON C.[$Id] = SI.Client
INNER JOIN dbo.Site AS S ON SI.Site = S.[$Id]
LEFT OUTER JOIN dbo.Contract AS CT ON SI.Contract = CT.[$Id]
LEFT OUTER JOIN dbo.ViewGoodsLocation AS L ON G.Gid = L.Gid
LEFT OUTER JOIN dbo.ViewGoodsWeight AS W ON G.Gid = W.Gid
LEFT OUTER JOIN dbo.ViewGoodsQuantity AS Q ON G.Gid = Q.Gid
LEFT OUTER JOIN dbo.ViewGoodsSingleArticle AS VGSA ON G.Gid = VGSA.Gid
LEFT OUTER JOIN dbo.ViewGoodsStockType AS VGST ON VGST.Gid = G.Gid
使用参数Client或参数Lid查询View时,一切都运行良好。 但是,如果我尝试将它们中的两个混合在一起,则View会超时而没有结果。 以下是获取超时的查询:
SELECT [t0].[Gid], [t0].[FirstSiteInId], [t0].[FirstSiteInDate], [t0].[FirstSiteInComments], [t0].[FirstSiteId], [t0].[FirstSiteRefex], [t0].[ClientId], [t0].[ClientRefex], [t0].[Contract], [t0].[ContractRefex], [t0].[SiteId], [t0].[SiteRefex], [t0].[Lid], [t0].[Weight], [t0].[Quantity], [t0].[Article], [t0].[ArticleName], [t0].[StockType], [t0].[StockTypeRefex]
FROM [ViewGoods] AS [t0]
WHERE ([t0].[Lid] IS NOT NULL) AND (([t0].[ClientId]) = 70)
我哪里出错?
编辑:我在此处列出了实际执行计划http://pastebin.com/PMY0aLE1。
答案 0 :(得分:2)
从您发布的查询计划中,它似乎正在访问10个表
文章,客户,合同,商品,GoodsArticle,GoodsEvent,Site,SiteIn,StockType,StockTypeContract
您的结果是否真的需要所有这些,或者其中任何一个都只是您正在加入的视图中的人工制品?
计划中有25个根节点用于这10个表,所以肯定会有一些表被访问多次,这看起来非常浪费。
您可以在计划的这一部分中看到(最多可增加40%的成本),MoneyEvent似乎被访问了三次。我很确定你是否能够摆脱那些能够巩固这一点的观点。
Portion of plan http://img245.imageshack.us/img245/4105/executionplan.png
我认为目前这个计划正在做这样的事情
SELECT Query3.Gid, Query3.SiteId, Query3.Lid, Query3.Expr1017
FROM
(
SELECT
Gid,
SUM(CASE WHEN Type ='SO' THEN -Quantity ELSE Quantity END) AS Expr1017
FROM GoodsEvent
WHERE Type IN('AQ','SI','SO') AND IsDeleted = 0
GROUP BY Gid
) Query1
JOIN
(
SELECT
Gid,
MAX(EventOn) AS Expr1014
FROM GoodsEvent
WHERE IsDeleted = 0
GROUP BY Gid
) Query2 ON Query1.GID = Query2.GID
JOIN
(
SELECT
GoodsEvent.Gid,
GoodsEvent.EventOn,
GoodsEvent.SiteId,
GoodsEvent.Lid
FROM GoodsEvent WHERE IsDeleted = 0
) Query3 ON Query3.gid=Query2.gid AND Query3.EventOn = Query2.Expr1014
可能值得测试这是否在语义上是等效的并且执行得更好
;WITH X AS
(
SELECT Gid,
SiteId,
Lid,
RANK() OVER (PARTITION BY Gid ORDER BY EventOn DESC) AS RN,
Type
FROM GoodsEvent
WHERE IsDeleted = 0
)
SELECT Gid,SiteId, Lid,
SUM(CASE WHEN Type ='SO' THEN -Quantity ELSE Quantity END)
OVER(PARTITION BY Gid) AS Expr1017,
FROM X WHERE RN=1 AND Type IN('AQ','SI','SO')
答案 1 :(得分:1)
如果您想要性能,则视图不应引用其他视图。这只是糟糕的设计。您不应该使用视图来执行此操作。执行此操作时,必须先完全实现这些视图,然后才能创建记录集。因此,对于可能200个最终记录,您可能需要调整几十亿。这会让事情变得非常缓慢,我发现当人们使用这种技术时,如果你一直按照视图一直到底,你经常会在同一个表中多次调用相同的数据。不要以这种方式使用视图。如果必须使用视图,则直接访问表,不要调用其他视图。这是一条你不想失望的道路,我们几乎失去了一个多元化的客户,因为有人设计了这种方式,而不是使用良好的数据访问方法。
这是有保证的,无法修复它会导致数据库最终戛然而止的性能问题。这是一个不好的设计时期,必须尽快改变。
答案 2 :(得分:0)
哦,哦......
我可以在您的视图定义中看到您正在加入至少9个其他数据结构,这些数据结构似乎也是视图(因此可能会有更多的表连接)。
这可能不是您想要听到的答案,但如果您需要将这么多数据结构加在一起,那么在设计时就会出现问题。
我的建议是你回到绘图板并重新考虑这个数据库的设计。
编辑:其他想法..
考虑到当您执行经常要求您连接多个表的查询时,这些是索引视图的候选者,即物化结构,它们实际上是表。定期执行大量连接操作会导致查询性能不佳,但可扩展性有限。
请记住,规范化是良好数据库设计的起点,它不一定是您的终点。