Bagi saya tampaknya where
klausa dalam kueri memberikan masalah, dan merupakan penyebab dari estimasi rendah, bahkan jika OPTION(RECOMPILE)
digunakan.
Saya membuat beberapa data uji, dan pada akhirnya muncul dengan dua solusi, menyimpan ID
bidang dari resources
salah satu variabel (jika selalu unik) atau tabel temp, jika kita dapat memiliki lebih dari satu ID
.
Catatan uji dasar
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
Masukkan nilai 'Seek', untuk mendapatkan perkiraan hasil yang sama seperti OP (1300 catatan)
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
Ubah statistik & Perbarui statistik untuk mencocokkan OP
ALTER DATABASE StackOverflow SET COMPATIBILITY_LEVEL = 120;
UPDATE STATISTICS settings WITH FULLSCAN;
UPDATE STATISTICS resources WITH FULLSCAN;
Permintaan asli
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
Perkiraan saya bahkan lebih buruk , dengan satu baris perkiraan, sedangkan 1300 dikembalikan. Dan seperti kata OP, tidak masalah jika saya tambahkanOPTION(RECOMPILE)
Satu hal penting yang perlu diperhatikan, adalah bahwa ketika kita menyingkirkan klausa di mana estimasi adalah 100% benar, yang diharapkan karena kita menggunakan semua data di kedua tabel.
Saya memaksa indeks hanya untuk memastikan kami menggunakan yang sama seperti pada permintaan sebelumnya, untuk membuktikan maksudnya
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
Seperti yang diharapkan, perkiraan bagus .
Jadi, apa yang bisa kita ubah untuk mendapatkan estimasi yang lebih baik tetapi masih mencari nilai-nilai kita?
JIKA @UID unik, seperti dalam contoh OP memberi, kita bisa menempatkan tunggal id
yang dikembalikan dari resources
dalam variabel, kemudian mencari variabel itu dengan 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);
Yang memberikan perkiraan akurat 100%
Tetapi bagaimana jika ada banyak sumber daya di dalam sumber daya?
tambahkan beberapa data uji
INSERT INTO Resources(ResourceUID)
VALUES (38);
go 50
Ini bisa diselesaikan dengan tabel temp
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
Lagi dengan perkiraan yang akurat .
Ini dilakukan dengan dataset saya sendiri, YMMV.
Ditulis dengan sp_executesql
Dengan variabel
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
Dengan meja temp
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
Masih 100% perkiraan yang benar pada pengujian saya
select r.id, LEFT(remark, 512)
(atau apa pun panjang substring yang masuk akal).