我有一個巨大的視圖,使用UNION ALL
連接了許多查詢,並且每個查詢的第一列都是常量。打開查詢在視圖中運行
例如
CREATE VIEW M AS (
SELECT 'A' ID, Value FROM A
UNION ALL
SELECT 'B' ID, Value FROM B
...
)
的查詢是在現實中更復雜,但這裏的目的只是爲了在這樣運行了哪些查詢切換:
SELECT * FROM M WHERE ID = 'A'
執行計劃表明該查詢不匹配ID
永不跑步。
我認爲這是一個非常好的功能?我可以用它來結合通過相同的視圖查詢不同但相似的東西。
不過,我結束了一個更好的執行計劃,如果查詢針對CTE這樣的:
WITH M AS (
SELECT 'A' ID, Value FROM A
UNION ALL
SELECT 'B' ID, Value FROM B
...
)
SELECT * FROM M WHERE ID = 'A'
這裏的實際查詢的部分樣本:
SELECT CONVERT(char(4), 'T ') EntityTypeID, SystemID, TaskId EntityID
FROM [dbo].[Task]
UNION ALL
SELECT CONVERT(char(4), 'T ') EntityTypeID, s.SystemID, [dbo].[Task].TaskId EntityID
FROM [dbo].[Task]
INNER JOIN [dbo].[System] s ON s.MasterSystemID = [dbo].[Task].SystemID
INNER JOIN SystemEntitySettings ON SystemEntitySettings.SystemID = s.SystemID
AND SystemEntitySettings.EntityTypeID = 'T '
AND SystemEntitySettings.IsSystemPrivate = 0
鑑於如果我運行類似於WHERE EntityTypeiD <> 'T'
的東西,它會忽略第一個查詢,但完成第二個查詢(從不返回任何實際的行)。
我遇到的問題,或者說更確切地說,我的問題是,爲什麼它不能完全從視圖中消除查詢,而在CTE情況下這樣做呢?
編輯
我觀察到一些有趣的事情,到目前爲止,我不排除與參數化的交易,但我也可以通過指定查詢提示(顯然任何會做)achive的desiered效果或將第二個連接重寫爲IN謂詞,因爲它只是一個過濾器。
INNER JOIN SystemEntitySettings ON SystemEntitySettings.SystemID = s.SystemID
AND SystemEntitySettings.EntityTypeID = 'T '
AND SystemEntitySettings.IsSystemPrivate = 0
... ...變得
WHERE s.SystemID IN (
SELECT SystemID
FROM dbo.SystemEntitySettings
WHERE EntityTypeID = 'T ' AND IsSystemPrivate = 0
)
但是,下面的查詢具有同樣的問題。它看起來好像和JOIN操作有關。 (注:與[組]考慮在此查詢的地方附加JOIN)
SELECT CONVERT(char(4), 'CF ') EntityTypeID, s.SystemID, [dbo].[CareerForum].GroupID EntityID
FROM [dbo].[CareerForum]
INNER JOIN [dbo].[Group] ON [dbo].[Group].GroupID = [dbo].[CareerForum].GroupID
INNER JOIN [dbo].[System] s ON s.MasterSystemID = [dbo].[Group].SystemID
WHERE s.SystemID IN (SELECT SystemID FROM dbo.SystemEntitySettings WHERE EntityTypeID = 'CF ' AND IsSystemPrivate = 0)
重現
下面的腳本可以用來重現該問題。請注意,執行計劃與查詢提示一起運行時是否完全不同,或者視圖是否使用cte(desiered結果)運行。
CREATE DATABASE test_jan_20
USE test_jan_20
create table source (
x int not null primary key,
)
insert into source values (1)
insert into source values (2)
insert into source values (3)
insert into source values (4)
insert into source values (5)
insert into source values (6)
create table other (
y int not null primary key,
)
insert into other values (1)
insert into other values (2)
insert into other values (3)
insert into other values (4)
insert into other values (5)
insert into other values (6)
create view dummy AS (
SELECT 'A' id, x, NULL y
FROM SOURCE
WHERE x BETWEEN 1 AND 2
UNION ALL
SELECT 'B' id, x, NULL y
FROM SOURCE
WHERE x BETWEEN 3 AND 4
UNION ALL
SELECT 'B' id, source.x, y
FROM SOURCE
INNER JOIN other ON y = source.x
INNER JOIN source s2 ON s2.x = y - 1 --i need this join for the issue to occur in the execution plan
WHERE source.x BETWEEN 5 AND 6
)
GO
--this one fails to remove the JOIN, not OK
SELECT * FROM dummy WHERE id = 'c'
--this is OK
SELECT * FROM dummy WHERE id = 'c' OPTION (HASH JOIN) --NOTE: any query hint seems to do the trick
--this is OK
;
WITH a AS (
SELECT 'A' id, x, NULL y
FROM SOURCE
WHERE x BETWEEN 1 AND 2
UNION ALL
SELECT 'B' id, x, NULL y
FROM SOURCE
WHERE x BETWEEN 3 AND 4
UNION ALL
SELECT 'B' id, source.x, y
FROM SOURCE
INNER JOIN other ON y = source.x
INNER JOIN source s2 ON s2.x = y - 1 --i need this join for the issue to occur in the execution plan
WHERE source.x BETWEEN 5 AND 6
)
SELECT * FROM a WHERE id = 'c'
是否使用字符串字面量在這兩種情況下或者您使用的參數?如果兩者的字符串文字是否都強制在服務器上打開參數設置? – 2011-01-20 00:07:51
應該選擇「T」的聯合查詢兩個分支? – RichardTheKiwi 2011-01-20 01:20:00
@Martin - 文字不強制參數化。 @cyberkiwi - 這只是整個查詢的一小部分,還有很多其他查詢都是使用UNION ALL連接的,這兩個都應該選擇'T' – 2011-01-20 07:18:27