J'ai une requête comme celle-ci:
DELETE FROM tblFEStatsBrowsers WHERE BrowserID NOT IN (
SELECT DISTINCT BrowserID FROM tblFEStatsPaperHits WITH (NOLOCK) WHERE BrowserID IS NOT NULL
)
tblFEStatsBrowsers a 553 lignes.
tblFEStatsPaperHits a 47.974.301 lignes.
tblFEStatsBrowsers:
CREATE TABLE [dbo].[tblFEStatsBrowsers](
[BrowserID] [smallint] IDENTITY(1,1) NOT NULL,
[Browser] [varchar](50) NOT NULL,
[Name] [varchar](40) NOT NULL,
[Version] [varchar](10) NOT NULL,
CONSTRAINT [PK_tblFEStatsBrowsers] PRIMARY KEY CLUSTERED ([BrowserID] ASC)
)
tblFEStatsPaperHits:
CREATE TABLE [dbo].[tblFEStatsPaperHits](
[PaperID] [int] NOT NULL,
[Created] [smalldatetime] NOT NULL,
[IP] [binary](4) NULL,
[PlatformID] [tinyint] NULL,
[BrowserID] [smallint] NULL,
[ReferrerID] [int] NULL,
[UserLanguage] [char](2) NULL
)
Il existe un index clusterisé sur tblFEStatsPaperHits qui n'inclut pas BrowserID. L'exécution de la requête interne nécessitera donc une analyse complète de la table de tblFEStatsPaperHits - ce qui est totalement OK.
Actuellement, une analyse complète est exécutée pour chaque ligne dans tblFEStatsBrowsers, ce qui signifie que j'ai 553 analyses complètes de la table de tblFEStatsPaperHits.
La réécriture dans un fichier WHERE EXISTS ne change pas le plan:
DELETE FROM tblFEStatsBrowsers WHERE NOT EXISTS (
SELECT * FROM tblFEStatsPaperHits WITH (NOLOCK) WHERE BrowserID = tblFEStatsBrowsers.BrowserID
)
Cependant, comme l'a suggéré Adam Machanic, l'ajout d'une option HASH JOIN donne un plan d'exécution optimal (un seul balayage de tblFEStatsPaperHits):
DELETE FROM tblFEStatsBrowsers WHERE NOT EXISTS (
SELECT * FROM tblFEStatsPaperHits WITH (NOLOCK) WHERE BrowserID = tblFEStatsBrowsers.BrowserID
) OPTION (HASH JOIN)
Maintenant, ce n’est plus une question de solution: je peux utiliser OPTION (HASH JOIN) ou créer une table temporaire manuellement. Je me demande davantage pourquoi l'optimiseur de requêtes utiliserait jamais le plan actuel.
Le QO n'ayant aucune statistique dans la colonne BrowserID, j'imagine qu'il suppose le pire - 50 millions de valeurs distinctes, nécessitant ainsi une table de travail en mémoire / tempdb assez importante. En tant que tel, le moyen le plus sûr consiste à effectuer des analyses pour chaque ligne dans tblFEStatsBrowsers. Il n'y a pas de relation de clé étrangère entre les colonnes de BrowserID dans les deux tables. Le QO ne peut donc déduire aucune information de tblFEStatsBrowsers.
Est-ce aussi simple que cela puisse paraître, la raison?
Mise à jour 1
Pour donner quelques statistiques: OPTION (HASH JOIN):
208.711 lectures logiques (12 scans)
OPTION (LOOP JOIN, HASH GROUP):
11.008.698 lectures logiques (~ analyse par ID de navigateur (339))
Aucune option:
11.008.775 lectures logiques (~ analyse par ID de navigateur (339))
Mise à jour 2
Excellentes réponses à toutes et à tous - merci! Difficile d'en choisir un seul. Bien que Martin ait été le premier et que Remus fournisse une excellente solution, je dois la donner au Kiwi pour ne pas perdre de vue les détails :)