私は多くのクエリを連結して、すべてのクエリの最初の列が一定である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
は実行されません。
私は、これは同じビューを通して異なるが類似したものを照合するのに使うことができる、本当にいいと思った。
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
考える:
ここWITH M AS (
SELECT 'A' ID, Value FROM A
UNION ALL
SELECT 'B' ID, Value FROM B
...
)
SELECT * FROM M WHERE ID = 'A'
は、実際のクエリの一部のサンプルです:
しかし、私はこのようなCTEに対して問い合わせる場合でも、より良い実行計画で終わりますよWHERE EntityTypeiD <> 'T'
のようなものを実行した場合、最初のクエリは完全に無視されますが、実際の行は返されません。
CTEのケースでは、ビューからクエリを完全に排除できないのはなぜですか?私はこれまでのところ、私はパラメータで取引を除外ませんが、私はまた、クエリヒントを指定するいずれかの方法でdesiered効果をachiveことができますいくつかの興味深いことを観察してきました
はEDIT
(どうやらいずれかが行います)、または2番目の結合は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の操作にいくつかの方法が関係しているかのように見えます。
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)
再現
(追加は、[グループ]は、このクエリで起きているとのJOIN注)次のスクリプトは、問題を再現するために使用することができます。クエリのヒントを使用してクエリを実行する場合、またはビューがcte(desiered result)を使用して実行されている場合、実行計画が完全に異なることに注目してください。
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'
どちらの場合でも文字列リテラルを使用していますか、またはパラメータを使用していますか?どちらの文字列リテラルでも、サーバー上のパラメータ化を強制的にオンにしていますか? –
は、 'T'を選択するはずの組合クエリの両方の分岐ですか? – RichardTheKiwi
@Martin - リテラルは強制的なパラメータ化をしません。 @cyberkiwi - これはクエリ全体の一部ですが、UNION ALLを使用してすべて連結された他の多くのクエリがありますが、これらの2つはどちらも 'T' –