2012-02-08 2 views
3

Я использую Firebird 2.1 и я нужна помощь оптимизируя этот запрос: (возможно, путем замены IN-s с JOINS или что-то, чтобы ускорить его, так как это очень медленно)Как оптимизировать этот запрос в Firebird 2.1?

SELECT ClientID, ClientType, ClientName 
FROM Clients 
WHERE 
    (
     AccessRights = 0 OR 
     OwnerUserID = :uid OR 
     (
      AccessRights = 2 AND 
      ClientID IN (SELECT ClientID 
          FROM ClientRights 
          WHERE UserID = :uid) 
     ) 
    ) 
    AND ClientID IN (SELECT CC.ClientID 
        FROM CaseClients CC 
        WHERE CC.CaseID IN (SELECT DISTINCT CaseID 
             FROM TimeSheet 
             WHERE IsBilled = 0) 
         AND CC.ClientToBill = 1 
         AND (SELECT BillingType 
           FROM Cases 
           WHERE CaseID = CC.CaseID) = 2 
    ); 

Спасибо!

+0

Вы уже добавили индексы в поля, которые вы запрашиваете, чтобы ускорить все это? – Iridio

+1

Я не могу говорить за firebird, но я знаю, что в некоторых реализациях использование EXISTS вместо IN быстрее. – Malachi

+0

Я знаю, что на SQL-сервере оптимизатор обычно лучше работает с 'AND', чем предикаты' OR', и иногда можно повысить производительность, преобразуя 'OR' в логически эквивалентную' AND' –

ответ

0

Это может ускорить его немного, но убедившись, что у вас есть индексацию правильно также поможет ..

SELECT C.ClientID, C.ClientType, C.ClientName 
FROM Clients C 
INNER JOIN CaseClients CC ON C.ClientID = CC.ClientID AND CC.ClientToBill = 1 
INNER JOIN TimeSheet TS ON CC.CaseID = TS.CaseID AND TS.IsBilled = 0 
INNER JOIN Cases CS ON CC.CaseID = CS.CaseId AND CS.BillingType = 2 
WHERE AccessRights = 0 
    OR OwnerUserID = :uid 
    OR 
     (
      AccessRights = 2 AND 
      ClientID IN (SELECT ClientID 
          FROM ClientRights 
          WHERE UserID = :uid) 
     ) 
    ) 
0
SELECT DISTINCT 
     c.ClientID 
     ,c.ClientType 
     ,c.ClientName 
    FROM Clients c 
INNER JOIN CaseClients cc 
    ON c.ClientID = cc.ClientID 
INNER JOIN TimeSheet ts 
    ON cc.CaseID = ts.CaseID 
INNER JOIN Cases ca 
    ON cc.CaseID = ca.CaseID 
WHERE ts.IsBilled = 0 
    AND cc.ClientToBill = 1 
    AND ca.BillingType = 2 
    AND (c.AccessRights = 0 OR 
     c.OwnerUserID = :uid OR 
     c.AccessRights = 2 AND c.ClientID IN (SELECT cr.ClientID 
               FROM ClientRights cr 
               WHERE cr.UserID = :uid) 
     ) 
0

По моему мнению, это было бы аккуратнее и быстрее:

SELECT ClientID, ClientType, ClientName 
FROM Clients C, CaseClients CC, TimeSheet TS, Cases CA 
WHERE C.ClientID = CC.ClientID 
AND CC.CaseID = TS.CaseID 
AND CC.CaseID = CA.CaseID 
AND TS.IsBilled = 0 
AND  CC.ClientToBill = 1 
AND  CA.BillingType = 2 
AND  (C.AccessRights = 0 OR C.OwnerUserID = :uid OR (C.AccessRights = 2 AND  C.ClientID IN 
(SELECT ClientID FROM ClientRights WHERE UserID = :uid))) 
1
SELECT ClientID, ClientType, ClientName FROM Clients 
WHERE 
(
    AccessRights = 0 OR 
    OwnerUserID = :uid OR 
    (
     AccessRights = 2 AND 
     EXISTS(SELECT * FROM ClientRights r WHERE r.UserID = :uid and r.ClientId=Clients.ClientID) 
    ) 
) 
AND EXISTS(SELECT * 
       FROM CaseClients CC 
       WHERE 
       CC.ClientID=Clients.ClientID and 
        EXISTS(SELECT * FROM TimeSheet 
          WHERE IsBilled = 0 and TimeSheet.CaseID=CC.CaseID) 
        AND CC.ClientToBill = 1 
        AND EXISTS(SELECT BillingType 
          FROM Cases 
          WHERE CaseID = CC.CaseID and BillingType=2) 
); 
Смежные вопросы