儘管實現的樹結構在SQL 2005服務器數據庫,查詢響應時間太長使用時(以下查詢談話超過5秒) LIKE子句加上EXISTS子句。在[UserSiteRight_T]優化數據庫模式/索引使用LIKE時和EXISTS子句
CREATE TABLE [dbo].[UserSiteRight_T](
[UserID_i] [int] NOT NULL
, [SiteID_i] [int] NOT NULL
, CONSTRAINT [PKC_UserSiteRight_UserIDSiteID] PRIMARY KEY CLUSTERED ([UserID_i] ASC, [SiteID_i] ASC)
, CONSTRAINT [FK_UserSiteRight_UserID] FOREIGN KEY([UserID_i]) REFERENCES [dbo].[User_T] ([ID_i])
, CONSTRAINT [FK_UserSiteRight_SiteID] FOREIGN KEY([SiteID_i]) REFERENCES [dbo].[Site_T] ([ID_i])
)
的行數(權利)爲UserID_i = 2484:[SitePath_T]和[UserSiteRight_T] -
慢查詢涉及兩個表表是相當小:545
(UserID_i = 2484被隨機選擇的)
此外,數據庫是相對較小 - 在[SitePath_T]表只有23000行:)
CREATE TABLE [dbo].[SitePath_T] (
[SiteID_i] INT NOT NULL,
[Path_v] VARCHAR(255) NOT NULL,
CONSTRAINT [PK_SitePath_PathSiteID] PRIMARY KEY CLUSTERED ([Path_v] ASC, [SiteID_i] ASC),
CONSTRAINT [AK_SitePath_Path] UNIQUE NONCLUSTERED ([Path_v] ASC),
CONSTRAINT [FK_SitePath_SiteID] FOREIGN KEY([SiteID_i]) REFERENCES [Site_T] ([ID_i])
DB Schema http://i46.tinypic.com/258aqfm.png
我試圖讓只有SiteIDs其中有子網站accessib樂受到了一定用戶名(由[UserSiteRight_T]表所示)爲:
SELECT sp.SiteID_i
FROM SitePath_t sp
WHERE EXISTS (SELECT *
FROM [dbo].[SitePath_T] usp
, [dbo].[UserSiteRight_T] uusr
WHERE uusr.SiteID_i = usp.SiteID_i
AND uusr.UserID_i = 2484
AND usp.Path_v LIKE sp.Path_v+'%')
下面你可以找到其中僅需要列sp.SiteID_i的結果的一部分/返回 - 我也加入相關的相應Path_v,UserSiteRight_T。SiteID_i其中userid = 2484和相應SitePath_TSiteID_i和Path_v匹配LIKE條件:
|--Nested Loops(Left Semi Join, WHERE:([MyTestDB].[dbo].[SitePath_T].[Path_v] as [usp].[Path_v] like [Expr1007]))
|--Compute Scalar(DEFINE:([Expr1007]=[MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%', [Expr1008]=LikeRangeStart([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%'), [Expr1009]=LikeRangeEnd([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%'), [Expr1010]=LikeRangeInfo([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%')))
| |--Index Scan(OBJECT:([MyTestDB].[dbo].[SitePath_T].[AK_SitePath_Path] AS [sp]))
|--Table Spool
|--Hash Match(Inner Join, HASH:([uusr].[SiteID_i])=([usp].[SiteID_i]))
|--Clustered Index Seek(OBJECT:([MyTestDB].[dbo].[UserSiteRight_T].[PKC_UserSiteRight_UserIDSiteID] AS [uusr]), SEEK:([uusr].[UserID_i]=(2484)) ORDERED FORWARD)
|--Index Scan(OBJECT:([MyTestDB].[dbo].[SitePath_T].[AK_SitePath_Path] AS [usp]))
:
sp.SiteID_i sp.Path_v [UserSiteRight_T].SiteID_i usp.SiteID_i usp.Path_v
1 '1.' NULL 10054 '1.10054.'
10054 '1.10054.' 10054 10054 '1.10054.'
10275 '1.10275.' 10275 10275 '1.10275.'
1533 '1.1533.' NULL 2697 '1.1533.2689.2693.2697.'
2689 '1.1533.2689.' NULL 2697 '1.1533.2689.2693.2697.'
2693 '1.1533.2689.2693.' NULL 2697 '1.1533.2689.2693.2697.'
2697 '1.1533.2689.2693.2697.' 2697 2697 '1.1533.2689.2693.2697.'
1580 '1.1580.' NULL 1581 '1.1580.1581.'
1581 '1.1580.1581.' 1581 1581 '1.1580.1581.'
1585 '1.1580.1581.1585.' 1585 1585 '1.1580.1581.1585.'
222 '1.222.' 222 222 '1.222.'
223 '1.222.223.' 223 223 '1.222.223.'
224 '1.222.223.224.' 224 224 '1.222.223.224.'
3103 '1.3103.' NULL 3537 '1.3103.3529.3533.3537.'
3529 '1.3103.3529.' NULL 3537 '1.3103.3529.3533.3537.'
3533 '1.3103.3529.3533.' NULL 3537 '1.3103.3529.3533.3537.'
3537 '1.3103.3529.3533.3537.' 3537 3537 '1.3103.3529.3533.3537.'
用於上述查詢執行計劃
而重寫的查詢:
SELECT DISTINCT
sp.SiteID_i
FROM [dbo].[SitePath_t] sp
, [dbo].[SitePath_T] usp
, [dbo].[UserSiteRight_T] uusr
WHERE (uusr.SiteID_i = usp.SiteID_i
AND uusr.UserID_i = 2484
AND usp.Path_v LIKE sp.Path_v+'%')
ORDER BY SiteID_i ASC
執行計劃:
|--Hash Match(Aggregate, HASH:([sp].[SiteID_i]))
|--Nested Loops(Inner Join, WHERE:([MyTestDB].[dbo].[SitePath_T].[Path_v] as [usp].[Path_v] like [Expr1006]))
|--Hash Match(Inner Join, HASH:([uusr].[SiteID_i])=([usp].[SiteID_i]))
| |--Clustered Index Seek(OBJECT:([MyTestDB].[dbo].[UserSiteRight_T].[PKC_UserSiteRight_UserIDSiteID] AS [uusr]), SEEK:([uusr].[UserID_i]=(2484)) ORDERED FORWARD)
| |--Index Scan(OBJECT:([MyTestDB].[dbo].[SitePath_T].[AK_SitePath_Path] AS [usp]))
|--Table Spool
|--Compute Scalar(DEFINE:([Expr1006]=[MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%', [Expr1007]=LikeRangeStart([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%'), [Expr1008]=LikeRangeEnd([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%'), [Expr1009]=LikeRangeInfo([MyTestDB].[dbo].[SitePath_T].[Path_v] as [sp].[Path_v]+'%')))
|--Index Scan(OBJECT:([MyTestDB].[dbo].[SitePath_T].[AK_SitePath_Path] AS [sp]))
各項指標都到位 - 數據庫引擎優化顧問不建議新的架構修改 - 但兩者查詢更多有5秒鐘後將返回正確的結果 - 和,因爲它是Ajax請求的響應 - 在更新導航樹時感覺(並且)非常緩慢
有關優化/修改數據庫模式/索引/查詢以獲得更快響應的任何建議?
謝謝
我不知道如果遞歸CTE的網站效果會更好,但我無法從你的數據告訴你怎麼知道哪根'SITEPATH_T'值。 – 2010-01-03 08:17:38