問(wèn)題描述:使用 SELECT 語(yǔ)句,輪詢表中的數(shù)據(jù),并且處理變量數(shù)據(jù)時(shí),假如有ORDER BY語(yǔ)句,則得不到想要的結(jié)果,但去掉ORDER BY,結(jié)果正常。具體的問(wèn)題表現(xiàn)參考下面的問(wèn)題重現(xiàn)代碼 問(wèn)題重現(xiàn)代碼-- 測(cè)試數(shù)據(jù)DECLARE @T TABLE(id int,value nvarchar(16))INSERT INTO @T SELECT
1, N'好人' UNION ALL SELECT 2, N'壞人' UNION ALL SELECT 3, N'吃飯' UNION ALL SELECT 4, N'垃圾' -- 賦值處理DECLARE @str nvarchar(4000)
SET @str = N'我不是一個(gè)好人,也不是垃圾'SELECT @str = REPLACE(@str, value, N'<u>' + value + N'</u>') FROM @T WHERE CHARINDEX(value, @str) > 0 --ORDER BY CHARINDEX(value, @str) DESCSELECT @str
/* -- 結(jié)果(當(dāng)賦值處理語(yǔ)句注釋掉ORDER BY 時(shí))我不是一個(gè)<u>好人</u>,也不是<u>垃圾</u>-- */ /* -- 結(jié)果(當(dāng)賦值處理語(yǔ)句加上ORDER BY 時(shí))我不是一個(gè)<u>好人</u>,也不是垃圾-- */
問(wèn)題分析:兩個(gè)處理語(yǔ)句的結(jié)果不同,通過(guò)查看它們的執(zhí)行計(jì)劃應(yīng)該可以看出原因所在,為此,通過(guò) SET SHOWPLAN_ALL ON輸出了兩種執(zhí)行語(yǔ)句的執(zhí)行計(jì)劃(僅StmtText部分,有愛(ài)好的讀者在自己的電腦上測(cè)試的時(shí)候,可以去了解其他部分的信息) StmtText Step DECLARE @str nvarchar(4000) SET @str = N'我不是一個(gè)好人,也不是垃圾'
SELECT @str = REPLACE(@str, value, N'<u>' + value + N'</u>') FROM @T WHERE CHARINDEX(value, @str) > 0 4 -- Compute Scalar(DEFINE:([EXPR1002]=replace([@str], @T.[value], '<u>'+@T.[value]+'</u>')))
3 -- Filter(WHERE:(charindex(@T.[value], [@str], NULL)>0)) 2
-- Table Scan(OBJECT:(@T)) 1
DECLARE @str nvarchar(4000) SET @str = N'我不是一個(gè)好人,也不是垃圾'
SELECT @str = REPLACE(@str, value, N'<u>' + value + N'</u>') FROM @T WHERE CHARINDEX(value, @str) > 0 ORDER BY CHARINDEX(value, @str) DESC 5 -- Sort(ORDER BY:([Expr1003] DESC)) 4
-- Compute Scalar(DEFINE:([Expr1002]=replace([@str], @T.[value], '<u>'+@T.[value]+'</u>'), [Expr1003]=charindex(@T.[value], [@str], NULL))) 3
-- Filter(WHERE:(charindex(@T.[value], [@str], NULL)>0)) 2
-- Table Scan(OBJECT:(@T)) 1 從上面的列表可以看出,兩種處理的最大差異,在于賦值前,是否有ORDER BY 子句,從一般的理解上,可能會(huì)認(rèn)為是否排序并不重要,但換個(gè)角度來(lái)看問(wèn)題,就比較輕易理解為什么有ORDER BY子句后得不到我們想要的結(jié)果了:當(dāng)有ORDER BY子句時(shí),對(duì)于SELECT @str = 這種賦值處理,SQL Server認(rèn)為賦值處理肯定只會(huì)保留最后一條記錄的處理結(jié)果,而ORDER BY子句確定了數(shù)據(jù)順序,也就知道最后一條記錄是那個(gè),因此只會(huì)處理ORDER BY的最后一條記錄。(讀者可以自行去測(cè)試一下,調(diào)整ORDER BY順序,看看結(jié)果是否與我的推論相符)當(dāng)沒(méi)有ORDER BY子句時(shí),因?yàn)闊o(wú)法確定數(shù)據(jù)順序,所以SQL Server必須掃描滿足條件的每條數(shù)據(jù)來(lái)得到結(jié)果,這樣每掃描一條記錄都會(huì)處理一次,所以結(jié)果是我們所預(yù)知的
問(wèn)題解決方法:修改處理語(yǔ)句,使查詢優(yōu)化器使用與我們需要結(jié)果一致的執(zhí)行方法,可以解決這個(gè)問(wèn)題。對(duì)于示例中的處理語(yǔ)句,可以調(diào)整如下:DECLARE @str nvarchar(4000)SET @str = N'我不是一個(gè)好人,也不是垃圾'SELECT @str = REPLACE(@str, value, N'<u>' + value + N'</u>')
FROM( SELECT TOP 100 PERCENT value FROM @T WHERE CHARINDEX(value, @str) > 0 ORDER BY CHARINDEX(value, @str) DESC)A
SELECT @str 補(bǔ)充:此問(wèn)題的結(jié)論只是筆者對(duì)于查詢分析的一個(gè)推論,并無(wú)相應(yīng)的官方文檔可以證實(shí),所以歡迎大家發(fā)表自己的看法