मेरे लिए यह प्रतीत होता है कि where
क्वेरी में खंड समस्या दे रहा है, और कम अनुमानों का कारण है, भले ही OPTION(RECOMPILE)
इसका उपयोग किया जाए।
मैंने कुछ परीक्षण डेटा बनाए, और अंत में दो समाधानों के साथ आया, 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
ओपी (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
ओपी से मिलान करने के लिए कंप्रेशर और अपडेट आँकड़े बदलें
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
मेरे अनुमान और भी खराब हैं , एक अनुमानित पंक्ति के साथ, जबकि 1300 वापस आ गए हैं। और जैसे ओपी ने कहा, इससे कोई फर्क नहीं पड़ता कि मैं जोड़ूंOPTION(RECOMPILE)
ध्यान देने वाली एक महत्वपूर्ण बात यह है कि जब हम अनुमान से मुक्त हो जाते हैं, तो अनुमान 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
जैसा कि अपेक्षित था, अच्छे अनुमान।
इसलिए, हम बेहतर अनुमान प्राप्त करने के लिए क्या बदल सकते हैं लेकिन फिर भी अपने मूल्यों की तलाश कर सकते हैं?
अगर @ यूआईडी अद्वितीय है, जैसा कि ओपी ने दिया था, तो हम एक वेरिएबल में id
से लौटाए गए सिंगल को लगा सकते थे resources
, फिर उस वेरिएबल पर एक ऑप्शन (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% सटीक अनुमान देता है
लेकिन क्या होगा अगर संसाधनों में कई रिसोर्सयूआईडी हों?
कुछ परीक्षण डेटा जोड़ें
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)
(या जो भी समझदार सबस्ट्रिंग लंबाई हो सकती है)।