Pour moi, il semble que la where
clause de la requête pose problème et soit la cause des faibles estimations, même si elle OPTION(RECOMPILE)
est utilisée.
J'ai créé quelques données de test, et finalement j'ai trouvé deux solutions, en stockant le ID
champ à partir resources
d'une variable (si elle est toujours unique) ou d'une table temporaire, si nous pouvons en avoir plus d'une ID
.
Enregistrements de test de base
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
Insérez les valeurs «Seek» pour obtenir le même jeu de résultats approximatif que OP (1300 enregistrements)
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
Modifier les statistiques de compatibilité et de mise à jour pour correspondre à OP
ALTER DATABASE StackOverflow SET COMPATIBILITY_LEVEL = 120;
UPDATE STATISTICS settings WITH FULLSCAN;
UPDATE STATISTICS resources WITH FULLSCAN;
Requête d'origine
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
Mes estimations sont encore pires , avec une ligne estimée, tandis que 1300 sont retournées. Et comme OP l'a dit, peu importe si j'ajouteOPTION(RECOMPILE)
Une chose importante à noter est que lorsque nous nous débarrassons de la clause where, les estimations sont correctes à 100%, ce qui est attendu car nous utilisons toutes les données dans les deux tableaux.
J'ai forcé les index juste pour m'assurer que nous utilisons les mêmes que dans la requête précédente, pour prouver le point
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
Comme prévu, de bonnes estimations.
Alors, que pourrions-nous changer pour obtenir de meilleures estimations tout en recherchant nos valeurs?
SI @UID est unique, comme dans l'exemple donné par OP, nous pourrions mettre le single id
qui a été renvoyé resources
dans une variable, puis rechercher cette variable avec une 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);
Ce qui donne des estimations précises à 100%
Mais que se passe-t-il s'il y a plusieurs resourceUID dans les ressources?
ajouter des données de test
INSERT INTO Resources(ResourceUID)
VALUES (38);
go 50
Cela pourrait être résolu avec une table temporaire
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
Encore une fois avec des estimations précises .
Cela a été fait avec mon propre jeu de données, YMMV.
Écrit avec sp_executesql
Avec une variable
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
Avec une table temporaire
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% toujours des estimations correctes sur mon test
select r.id, LEFT(remark, 512)
(ou quelle que soit la longueur de la sous-chaîne sensible).