Mir scheint, dass die where
Klausel in der Abfrage das Problem darstellt und die Ursache für die niedrigen Schätzungen ist, selbst wenn sie OPTION(RECOMPILE)
verwendet wird.
Ich habe einige Testdaten erstellt und am Ende zwei Lösungen gefunden, bei denen das ID
Feld resources
entweder in einer Variablen (wenn es immer eindeutig ist) oder in einer temporären Tabelle gespeichert wird, wenn wir mehr als eine haben können ID
.
Basistestaufzeichnungen
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
Fügen Sie die 'Seek'-Werte ein, um dieselbe ungefähre Ergebnismenge wie OP zu erhalten (1300 Datensätze).
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
Ändern Sie die Kompatibilitäts- und Aktualisierungsstatistik entsprechend dem OP
ALTER DATABASE StackOverflow SET COMPATIBILITY_LEVEL = 120;
UPDATE STATISTICS settings WITH FULLSCAN;
UPDATE STATISTICS resources WITH FULLSCAN;
Ursprüngliche Abfrage
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
Meine Schätzungen sind mit einer geschätzten Zeile noch schlechter , während 1300 zurückgegeben werden. Und wie OP sagte, spielt es keine Rolle, ob ich hinzufügeOPTION(RECOMPILE)
Es ist wichtig zu beachten, dass die Schätzungen zu 100% korrekt sind, wenn wir die where-Klausel entfernen, was erwartet wird, da wir alle Daten in beiden Tabellen verwenden.
Ich habe die Indizes gezwungen, nur um sicherzustellen, dass wir dieselben wie in der vorherigen Abfrage verwenden, um den Punkt zu beweisen
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
Wie erwartet gute Schätzungen.
Was könnten wir also ändern, um bessere Schätzungen zu erhalten und dennoch nach unseren Werten zu suchen?
WENN @UID eindeutig ist, wie im Beispiel, das OP gegeben hat, könnten wir die Single id
, von der zurückgegeben wurde, resources
in eine Variable einfügen und diese Variable dann mit einer OPTION (RECOMPILE) suchen.
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);
Das gibt 100% genaue Schätzungen
Was aber, wenn mehrere Ressourcen-UIDs in Ressourcen enthalten sind?
Fügen Sie einige Testdaten hinzu
INSERT INTO Resources(ResourceUID)
VALUES (38);
go 50
Dies könnte mit einer temporären Tabelle behoben werden
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
Wieder mit genauen Schätzungen .
Dies wurde mit meinem eigenen Datensatz YMMV durchgeführt.
Geschrieben mit sp_executesql
Mit einer Variablen
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
Mit einem temporären Tisch
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
Immer noch 100% korrekte Schätzungen zu meinem Test
select r.id, LEFT(remark, 512)
Vielleicht können Sie es versuchen (oder welche vernünftige Teilstringlänge auch immer sein mag).