Bana göre where
, sorgudaki tümcenin sorunu oluşturduğu ve OPTION(RECOMPILE)
kullanılsa bile düşük tahminlerin nedeni olduğu anlaşılıyor .
Bazı test verileri oluşturdum ve sonunda ID
alanı resources
bir değişken (her zaman benzersizse) veya bir geçici tablodan, birden fazla var ise depolayabilen iki çözüm ortaya çıktı ID
.
Temel test kayıtları
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 ile aynı yaklaşık sonuç kümesine ulaşmak için 'Seek' değerlerini girin (1300 kayıt)
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
Uyumluluk ve istatistikleri istatistikleri OP ile eşleşecek şekilde değiştirin
ALTER DATABASE StackOverflow SET COMPATIBILITY_LEVEL = 120;
UPDATE STATISTICS settings WITH FULLSCAN;
UPDATE STATISTICS resources WITH FULLSCAN;
Orijinal sorgu
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
Tahminlerim daha da kötüleşiyor , tahmin edilen bir satırla 1300 döndürülür. Ve OP'nin belirttiği gibi, ekleyip eklemediğim önemli değilOPTION(RECOMPILE)
Dikkat edilmesi gereken önemli bir nokta, nerede cümlesinden kurtulduğumuzda, tahminlerin% 100 doğru olduğu, bu da her iki tabloda da tüm verileri kullandığımızdan beklenen.
Dizinleri sadece önceki sorgudakiyle aynı kullandığımızdan emin olmak için zorladım, noktayı kanıtlamak için
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
Beklendiği gibi, iyi tahminler.
Öyleyse, daha iyi tahminler almak için yine de değerlerimizi araştırmak için neyi değiştirebiliriz?
@UID benzersizse, OP örneğinde id
olduğu gibi, döndürülen tek resources
değişkeni bir değişkene koyabilir ve ardından bir SEÇENEK (RECOMPILE) ile bu değişkeni arayabiliriz
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);
Bu da% 100 doğru tahminler verir
Ancak, kaynaklarda birden çok resourceUID varsa ne olur?
biraz test verisi ekle
INSERT INTO Resources(ResourceUID)
VALUES (38);
go 50
Bu geçici bir tablo ile çözülebilir
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
Yine doğru tahminlerle .
Bu kendi veri setim YMMV ile yapıldı.
Sp_executesql ile yazıldı
Değişken ile
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
Geçici masa ile
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
Testimde hala% 100 doğru tahminler
select r.id, LEFT(remark, 512)
(veya mantıklı alt dize uzunluğu ne olursa olsun).