Выберите время ожидания с 2 параметрами - PullRequest
2 голосов
/ 27 июля 2010

У меня есть следующий 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

При запросе этого View с параметром Client или параметром Lid по отдельности все работает хорошо.Но если я попытаюсь смешать их обоих, время просмотра закончится безрезультатно.Ниже запрос получает тайм-аут:

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.

Ответы [ 3 ]

2 голосов
/ 27 июля 2010

Из плана Query, который вы опубликовали, похоже, он обращается к 10 таблицам

Статья, Клиент, Контракт, Товары, ТоварыАртикул, Товары, Событие, Сайт, SiteIn, StockType, StockTypeContract

Все ли это на самом деле требуется для ваших результатов, или это просто артефакты того, к чему вы присоединяетесь?

В плане есть 10 корневых узлов для этих 10 таблиц, поэтому определенно к некоторым таблицам обращаются более одного раза, и это выглядит довольно расточительным образом.

Вы можете видеть в этой части плана (добавляется до 40% от стоимости) Похоже, что GoodsEvent доступен три раза. Я почти уверен, что если вы избавитесь от мнений, вы сможете закрепить это.

Часть плана 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 голос
/ 28 июля 2010

Представления никогда не должны ссылаться на другие представления, если вы хотите производительность. Это просто плохой дизайн. Вы не должны использовать представление для этого. Когда вы делаете это, он должен полностью материализовать эти представления, прежде чем он сможет создать набор записей. Так что, возможно, для 200 финальных записей вам, возможно, придется назвать несколько миллиардов. Это сильно замедлит ход событий, и я обнаружил, что когда люди используют эту технику, если вы прослеживаете взгляды до самого дна, вы часто вызываете одни и те же данные из одной и той же таблицы много-много раз. НЕ используйте вид таким образом. Если вам необходимо использовать представление, то обращайтесь к таблицам напрямую и не вызывайте другие представления. Это путь, по которому вы не хотите идти, мы почти потеряли многомиллионного клиента, потому что кто-то разработал этот способ вместо использования хороших методов доступа к данным.

Это гарантированный, но никак не способ исправить проблему с производительностью, из-за которой ваша база данных в конечном итоге остановится. Это ПЛОХОЙ период разработки, и он должен быть изменен как можно скорее.

0 голосов
/ 27 июля 2010

Э-э-э ......

Я вижу в вашем представлении определение, что вы присоединяетесь по крайней мере к 9 другим структурам данных, которые также выглядят как представления (так что может быть дополнительная таблицаприсоединяется к ним).

Вероятно, это не тот ответ, который вы захотите услышать, но если вам нужно объединить столько структур данных вместе, то во время разработки что-то пошло не так.

Я предлагаю вам вернуться к чертежной доске и переосмыслить дизайн этой базы данных.

Редактировать: Дополнительные мысли ..

Учтите, что при выполнении запросовкоторые регулярно требуют объединения нескольких таблиц, это кандидаты в индексированные представления, т.е. материализованные структуры, которые фактически являются таблицами.Регулярное выполнение большого количества операций объединения приводит к неэффективным запросам с ограниченной масштабируемостью.

Имейте в виду, что нормализация является отправной точкой для хорошего проектирования базы данных, она не обязательно должна быть вашей конечной точкой.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...