sql >> Database teknologi >  >> RDS >> Sqlserver

Hvorfor ignorerer Query Optimizer fuldstændigt indekserede visningsindekser?

tl;dr svar:Hvis du ikke specificerer NOEXPAND, aner forespørgselsoptimeringsværktøjet ikke, at du sender et simpelt valg fra en visning. Den skal matche udvidelsen af ​​din forespørgsel (hvilket er alt, den ser) med et eller andet visningsindeks. Vil formentlig ikke genere, når det er en fem-vejs joinforbindelse med en masse casts.

Vis indeksmatchning til en forespørgsel er et svært problem, og jeg mener, at dit synspunkt er for kompliceret til, at forespørgselsmotoren kan matche et indeks. Overvej dette en af ​​dine spørgsmål:

SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';

Det er indlysende for dig, at dette kan bruge et visningsindeks, men det er ikke den forespørgsel, forespørgselsmotoren ser. Visninger udvides automatisk, hvis du ikke angiver NOEXPAND, så dette er, hvad der går til forespørgselsmotoren:

SELECT ID, Code1 FROM (
    SELECT e.ID, 'NR'+CAST(c1.CODE as nvarchar(11)) as Code1, 'NR'+CAST(c2.CODE as nvarchar(11)) as Code2, 'NR'+CAST(c3.CODE as nvarchar(11)) as Code3, 'NR'+CAST(c4.CODE as nvarchar(11)) as Code4, 'NR'+CAST(c5.CODE as nvarchar(11)) as Code5
    FROM dbo.Entity e
        inner join  dbo.Classificator1 c1 on e.ID = c1.ID
        inner join  dbo.Classificator2 c2 on e.ID = c2.ID
        inner join  dbo.Classificator3 c3 on e.ID = c3.ID
        inner join  dbo.Classificator4 c4 on e.ID = c4.ID
        inner join  dbo.Classificator5 c5 on e.ID = c5.ID;
) AS V;

Forespørgselsmotoren ser denne komplicerede forespørgsel, og den har information (men sandsynligvis ikke SQL-udsigtsdefinitioner), der beskriver visningsindekser, der er blevet defineret. I betragtning af, at denne forespørgsel og visningsindekserne begge har flere sammenføjninger og casts, er matchning en hård opgave.

Husk, at du ved, at joinforbindelserne og matchene er identiske i denne forespørgsel og visningsindekserne, men det ved forespørgselsprocessoren ikke. Den behandler denne forespørgsel på samme måde, som hvis den forenede fem kopier af Classificator3, eller hvis en af ​​kolonnerne var 'NQ'+CAST(c2.CODE som varchar(12)). Visningsindeksmatcheren (forudsat at den gjorde ethvert forsøg på at matche denne komplicerede forespørgsel) ville være nødt til at matche alle detaljer i denne forespørgsel med detaljerne i viewindekser på de involverede tabeller.

Forespørgselsmotoren har som sit #1 mål at finde ud af en måde at udføre forespørgslen på effektivt. Det er sandsynligvis ikke designet til at bruge en masse tid på at forsøge at matche alle detaljer i en fem-vejs join og CASTs til et visningsindeks.

Hvis jeg skulle gætte, formoder jeg, at visningsindeksmatcheren ser, at resultatkolonnerne i forespørgslen ikke engang er kolonner i nogen underliggende tabel (på grund af CAST) og simpelthen ikke gider at prøve noget. Tilføjet :Jeg tager fejl. Jeg har lige prøvet Martins forslag om at opdatere statistik for at gøre forespørgslen dyr, og et visningsindeks blev matchet for nogle af disse forespørgsler uden NOEXPAND. View-matcheren er klogere, end jeg troede! Så problemet er, at visningsmatcheren sandsynligvis forsøger hårdere at matche en kompliceret forespørgsel, hvis omkostningerne er meget høje.

Brug NOEXPAND-tip i stedet for at forvente, at forespørgselsmotoren kan finde ud af, hvad der matcher her. NOEXPAND er absolut din ven, for så kan forespørgselsmotoren se

SELECT ID, Code1 FROM EntityView Where Code1 > 'NR%';

og det er umiddelbart indlysende for visningsindeksmatcheren, at der er et nyttigt indeks.

(Bemærk:Din SQL Fiddle-kode har alle 5 fremmednøglereferencer til den samme tabel, hvilket sandsynligvis ikke er, hvad du ønsker.)



  1. Integration af postgreSQL på WAMP

  2. MySQL-indekser – hvor mange er nok?

  3. Sådan finder du alle rækker med en NULL-værdi i en kolonne ved hjælp af PostgreSQL

  4. Er der en standardrækkefølge efter kolonne i SQL Server?