A me sembra che la where
clausola nella query stia dando il problema ed è la causa delle stime basse, anche se OPTION(RECOMPILE)
viene utilizzata.
Ho creato alcuni dati di test e alla fine ho trovato due soluzioni, memorizzando il ID
campo resources
in una variabile (se è sempre unica) o in una tabella temporanea, se ne possiamo avere più di una ID
.
Record di test di 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
Inserire i valori "Cerca" per ottenere lo stesso gruppo di risultati approssimativo dell'OP (1300 record)
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
Modifica la compatibilità e aggiorna le statistiche in modo che corrispondano a OP
ALTER DATABASE StackOverflow SET COMPATIBILITY_LEVEL = 120;
UPDATE STATISTICS settings WITH FULLSCAN;
UPDATE STATISTICS resources WITH FULLSCAN;
Query originale
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
Le mie stime sono anche peggiori , con una riga stimata, mentre vengono restituite 1300. E come affermato da OP, non importa se aggiungoOPTION(RECOMPILE)
Una cosa importante da notare è che quando ci liberiamo della clausola where le stime sono corrette al 100%, il che è previsto poiché stiamo utilizzando tutti i dati in entrambe le tabelle.
Ho costretto gli indici solo per assicurarmi di usare gli stessi della query precedente, per dimostrare il punto
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
Come previsto, buone stime.
Quindi, cosa potremmo cambiare per ottenere stime migliori ma cercare ancora i nostri valori?
Se @UID è univoco, come nell'esempio OP fornito, potremmo mettere il singolo da id
cui è stato restituito resources
in una variabile, quindi cercare quella variabile con un'OPZIONE (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);
Che fornisce stime accurate al 100%
Ma cosa succede se ci sono più risorseUID nelle risorse?
aggiungere alcuni dati di test
INSERT INTO Resources(ResourceUID)
VALUES (38);
go 50
Questo potrebbe essere risolto con una tabella temporanea
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
Ancora una volta con stime accurate .
Questo è stato fatto con il mio set di dati, YMMV.
Scritto con sp_executesql
Con una variabile
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
Con una tabella temporanea
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
Stime ancora corrette al 100% sul mio test
select r.id, LEFT(remark, 512)
(o qualsiasi lunghezza ragionevole della sottostringa potrebbe essere).