Domanda

Ho una semplice vista indicizzata. Quando chiedo contro, è piuttosto lento. Per prima cosa ti mostro gli schemi e gli indici. Quindi le semplici query. Finalmente un esame del piano di query.

Aggiornamento: prova della soluzione in fondo a questo post.

Schema

Ecco come appare: -

CREATE view [dbo].[PostsCleanSubjectView] with SCHEMABINDING AS
    SELECT PostId, PostTypeId, 
        [dbo].[ToUriCleanText]([Subject]) AS CleanedSubject
    FROM [dbo].[Posts]

Il mio udf ToUriCleanText sostituisce semplicemente vari caratteri con un carattere vuoto. Per esempio. sostituisce tutti i caratteri '#' con ''.

Quindi ho aggiunto due indici su questo: -

Indici

Indice chiave primaria (es. indice cluster)

CREATE UNIQUE CLUSTERED INDEX [PK_PostCleanSubjectView] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [PostId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

E un indice non cluster

CREATE NONCLUSTERED INDEX [IX_PostCleanSubjectView_PostTypeId_Subject] ON 
    [dbo].[PostsCleanSubjectView] 
(
    [CleanedSubject] ASC,
    [PostTypeId] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF,
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Ora, questo ha circa 25 KB di righe. Niente di grosso.

Quando faccio le seguenti domande, entrambe impiegano circa 4 secondi dispari. WTF? Questo dovrebbe essere ... praticamente istantaneo!

Query 1

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town'

Query 2 (aggiunto un altro elemento clausola where)

SELECT a.PostId
FROM PostsCleanSubjectView a 
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

Cosa ho fatto di sbagliato? L'UDF sta rovinando tutto? Ho pensato che, poiché ho indicizzato questa visione, sarebbe stata materializzata. Pertanto, non dovrebbe calcolare quella colonna di stringhe.

Ecco uno screenshot del piano di query, se questo aiuta: - alt text

Inoltre, noti l'indice che sta usando? Perché utilizza quell'indice?

Quell'indice è ...

CREATE NONCLUSTERED INDEX [IX_Posts_PostTypeId_Subject] ON [dbo].[Posts] 
(
    [PostTypeId] ASC,
    [Subject] ASC
)
WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, 
      SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, 
      ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
GO

Quindi sì, qualche idea gente?

Aggiornamento 1: schema aggiunto per udf.

CREATE FUNCTION [dbo].[ToUriCleanText]
(
    @Subject NVARCHAR(300)
)
RETURNS NVARCHAR(350) WITH SCHEMABINDING
AS 
BEGIN
   <snip>
   // Nothing insteresting in here. 
   //Just lots of SET @foo = REPLACE(@foo, '

Aggiornamento 2: Soluzione

Sì, era perché non stavo usando l'indice sulla vista e dovevo assicurarmi manualmente di non espandere la vista. Il server è SQL Server 2008 Standard Edition. La risposta completa è di seguito. Ecco la prova, WITH (NOEXPAND) alt text

Grazie a tutti per avermi aiutato a risolvere questo problema :)

, ''), etc. END

Aggiornamento 2: Soluzione

Sì, era perché non stavo usando l'indice sulla vista e dovevo assicurarmi manualmente di non espandere la vista. Il server è SQL Server 2008 Standard Edition. La risposta completa è di seguito. Ecco la prova, WITH (NOEXPAND) alt text

Grazie a tutti per avermi aiutato a risolvere questo problema :)

È stato utile?

Soluzione

Quale edizione di SQL Server? Credo che solo Enterprise e Developer Edition utilizzeranno automaticamente le visualizzazioni indicizzate, mentre le altre lo supportano utilizzando i suggerimenti per le query.

SELECT a.PostId
FROM PostsCleanSubjectView a WITH (NOEXPAND)
WHERE a.CleanedSubject = 'Just-out-of-town' AND a.PostTypeId = 1

Da Suggerimenti per le query (Transact SQL) su MSDN :

  

La vista indicizzata non viene espansa solo se si fa riferimento direttamente alla vista nella parte SELEZIONA della query e si specifica WITH (NOEXPAND) o WITH (NOEXPAND, INDEX (index_value [, ... n])).

Altri suggerimenti

Vedo un segno @ nel codice della query nel tuo piano di esecuzione. C'è una variabile stringa coinvolta.

Il server SQL ha un comportamento NASTY se il tipo della variabile stringa non corrisponde al tipo della colonna stringa nell'indice. Sql Server ... convertirà l'intera colonna in quel tipo, eseguirà la ricerca rapida e quindi eliminerà l'indice convertito in modo che possa eseguire di nuovo l'intera operazione alla prossima query.


Simon l'ha capito, ma ecco ulteriori dettagli utili: http: // msdn.microsoft.com/en-us/library/ms187373.aspx

  

Se una query contiene riferimenti a colonne presenti sia in una vista indicizzata che in tabelle di base, e Query Optimizer determina che l'utilizzo della vista indicizzata fornisce il metodo migliore per eseguire la query, Query Optimizer utilizza l'indice nella vista . Questa funzione è denominata corrispondenza della vista indicizzata ed è supportata solo nelle edizioni SQL Server Enterprise e Developer.

     

Tuttavia, affinché l'ottimizzatore consideri le viste indicizzate per la corrispondenza o utilizzi una vista indicizzata a cui fa riferimento il suggerimento NOEXPAND, le seguenti opzioni SET devono essere impostate su ON:

Quindi, ciò che sta accadendo qui è che la corrispondenza della vista indicizzata non funziona. Assicurati di utilizzare le edizioni Enterprise o Developer di Sql Server (molto probabilmente). Quindi controlla le opzioni SET in base all'articolo.

Di recente ho creato un ampio database contenente centinaia di milioni di record dei dettagli delle chiamate e ci sono alcune funzioni che stavo usando nelle query e nelle viste che ho trasformato in colonne calcolate persistenti. Questo ha funzionato molto meglio perché potevo indicizzare sulla colonna calcolata.

Non stavo usando SQL Enterprise, quindi non ho avuto l'opportunità di usare le viste indicizzate. La vista indicizzata dovrebbe essere in grado di indicizzare i risultati deterministici dell'UDF?

Sospetto che debba chiamare quella funzione per ogni riga prima che possa fare il confronto nella tua clausola where. Vorrei esporre l'oggetto, eseguire la query verificandola direttamente e vedere come vanno i tempi. In genere ho visto molta lentezza ogni volta che modifico un valore usando una funzione e poi lo uso nella clausola where ...

Quali vantaggi stai cercando utilizzando una vista indicizzata? Non è possibile indicizzare correttamente le tabelle stesse? Senza una buona giustificazione, stai aggiungendo complessità e chiedendo all'ottimizzatore di gestire più oggetti di database con meno flessibilità.

Hai valutato la stessa logica di query con indici standard?

Il mixaggio nella logica UDF confonde ancora di più le cose.

Se tutto ciò che vuoi è mantenere il valore di ritorno di un UDF, considera una colonna calcolata persistente piuttosto che una vista indicizzata.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top