如何在 Firebird 2.1 中优化此查询?
Posted
技术标签:
【中文标题】如何在 Firebird 2.1 中优化此查询?【英文标题】:How can I optimize this query in Firebird 2.1? 【发布时间】:2012-03-01 03:47:12 【问题描述】:我正在使用 Firebird 2.1,我需要一些帮助来优化此查询:(可能通过将 IN-s 替换为 JOINS 或其他方式来加快速度,因为它非常慢)
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
);
谢谢!
【问题讨论】:
您是否已经为要查询的字段添加了索引以加快整个过程? 我不能代表火鸟,但我知道在某些实现中,使用 EXISTS 而不是 IN 更快。 我知道在 SQL Server 中,优化器在使用AND
谓词时通常比 OR
表现更好,有时可以通过将 OR
转换为逻辑上等效的 AND
来提高性能跨度>
【参考方案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)
);
【讨论】:
【参考方案2】:这可能会加快速度,但确保索引正确也会有所帮助..
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)
)
)
【讨论】:
【参考方案3】: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)
)
【讨论】:
【参考方案4】:在我看来,这样会更整洁、更快:
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)))
【讨论】:
以上是关于如何在 Firebird 2.1 中优化此查询?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Firebird 2.1 中临时禁用表中的所有约束?
如何测量 Firebird 2.1 数据库上 blob 占用的空间量?
如何使用 C# Firebird 对数据库执行选择查询并将其显示在 shell 中?
Firebird 2.1 在某些数据库表中存储大量行是不是有效?