私にwhere
は、クエリの句が問題を引き起こしているように見え、たとえOPTION(RECOMPILE)
使用されていても、推定値が低い原因であると思われます。
私はいくつかのテストデータを作成し、最後に2つのソリューションを考え出し、ID
フィールドをresources
変数(常に一意の場合)または一時テーブル(複数の場合がある場合)に格納しましたID
。
基本試験記録
SET NOCOUNT ON
DECLARE @i int= 1;
WHILE @i <= 10000
BEGIN
INSERT INTO [dbo].[Settings]([resourceId],[typeID],remark)
VALUES(@i,@i,'KEPT THESE VALUES OUT BECAUSE IT WOULD CLUTTER THE EXAMPLES, VALUES OVER 8000 Chars entered here'); -- 23254 character length on each value
INSERT INTO [dbo].[Resources](resourceUID)
VALUES(@i);
SET @i += 1;
END
OP(1300レコード)と同じおおよその結果セットを取得するには、「シーク」値を挿入します。
INSERT INTO [dbo].[Settings]([resourceId],[typeID],remark)
VALUES(38,38,'KEPT THESE VALUES OUT BECAUSE IT WOULD CLUTTER THE EXAMPLES, VALUES OVER 8000 Chars entered here')
GO 1300
互換性を変更し、OPに合わせて統計を更新する
ALTER DATABASE StackOverflow SET COMPATIBILITY_LEVEL = 120;
UPDATE STATISTICS settings WITH FULLSCAN;
UPDATE STATISTICS resources WITH FULLSCAN;
元のクエリ
exec sp_executesql N'
select r.id
FROM Resources r
inner join Settings on resourceid=r.id
where resourceUID=@UID
ORDER BY typeID',
N'@UID int',
@UID=38
私の推定値はさらに悪く、1行が推定され、1300が返されます。そしてOPが述べたように、私が追加しても問題ではありませんOPTION(RECOMPILE)
注意すべき重要な点は、where句を取り除くと、推定値が100%正しいということです。これは、両方のテーブルのすべてのデータを使用しているため、予想されます。
ポイントを証明するために、前のクエリと同じものを使用することを確認するために、インデックスを強制しました
exec sp_executesql N'
select r.id,remark
FROM Resources r with(index([IX_UID]))
inner join Settings WITH(INDEX([IX_Test]))
on resourceid=r.id
ORDER BY typeID',
N'@UID int',
@UID=38
予想通り、良い見積もり。
では、より良い見積もりを得るために何を変更できるでしょうか?
OPの例のように、@ UIDが一意である場合は、id
返されたシングルresources
を変数に入れ、OPTION(RECOMPILE)を使用してその変数を検索できます。
DECLARE @UID int =38 , @RID int;
SELECT @RID=r.id from
Resources r where resourceUID = @UID;
SELECT @uid, remark
from Settings
where resourceId = @uid
Order by typeID
OPTION(RECOMPILE);
100%正確な見積もりが得られます
しかし、リソースに複数のresourceUIDがある場合はどうなりますか?
テストデータを追加する
INSERT INTO Resources(ResourceUID)
VALUES (38);
go 50
これは一時テーブルで解決できます
CREATE TABLE #RID (id int)
DECLARE @UID int =38
INSERT INTO #RID
SELECT r.id
from
Resources r where resourceUID = @UID
SELECT @uid, remark
from Settings s
INNER JOIN #RID r
ON r.id =s.resourceId
Order by typeID
OPTION(RECOMPILE)
DROP TABLE #RID
もう一度正確な見積もりを使用します。
これは私自身のデータセット、YMMVで行われました。
sp_executesqlで記述
変数あり
exec sp_executesql N'
DECLARE @RID int;
SELECT @RID=r.id from
Resources r where resourceUID = @UID;
SELECT @uid, remark
from Settings
where resourceId = @uid
Order by typeID
OPTION(RECOMPILE);',
N'@UID int',
@UID=38
一時テーブルあり
exec sp_executesql N'
CREATE TABLE #RID (id int)
INSERT INTO #RID
SELECT r.id
from
Resources r where resourceUID = @UID
SELECT @uid, remark
from Settings s
INNER JOIN #RID r
ON r.id =s.resourceId
Order by typeID
OPTION(RECOMPILE)
DROP TABLE #RID',
N'@UID int',
@UID=38
それでも私のテストでは100%正しい見積もり
select r.id, LEFT(remark, 512)
かもしれません(またはどんなサブセンスの長さでもいいかもしれません)。