Query eseguita in modo diverso su SQL 2005 vs SQL 2008R2


9

Nel mio ufficio, abbiamo una query che è piuttosto brutta, ma funziona abbastanza bene nella produzione e nell'ambiente di sviluppo (rispettivamente 20 secondi e 4 secondi). Tuttavia nel nostro ambiente di test ci vogliono oltre 4 ore. SQL2005 (+ ultime patch) è in esecuzione in produzione e sviluppo. SQL2008R2 è in esecuzione in fase di test.

Ho dato un'occhiata al Piano delle query e mostra che SQL2008R2 sta usando TempDB, tramite un Table Spool (lazy spool) per memorizzare le righe restituite dal server collegato. Il passaggio successivo mostra i loop annidati (anti-join semi sinistro) mentre consumano il 96,3% della query. La linea tra i due operatori è a 5.398 MB!

Il piano di query per SQL 2005 non mostra alcun utilizzo di tempdb e nessun utilizzo di Anti Anti Join sinistro.

Di seguito è riportato il codice igienizzato e l'esecuzione prevede il piano 2005 in alto, il 2008R2 in basso.

Cosa sta causando il drastico rallentamento e il cambiamento? Mi aspettavo di vedere un piano di esecuzione diverso, quindi non mi dà fastidio. Il drammatico rallentamento dei tempi di interrogazione è ciò che mi preoccupa.

Devo guardare l'hardware sottostante, dal momento che la versione 2008R2 utilizza tempdb devo dare un'occhiata a come ottimizzare l'utilizzo di quello?

C'è un modo migliore per scrivere la query?

Grazie per l'aiuto.

    INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE 
   (
    Alias2.FirstName + Alias2.LastName = dbo.fnRemoveNonLetter(Table1.FullName)
    AND NOT dbo.fnRemoveNonLetter(Table1.FullName) IS NULL
    AND NOT Alias2.FirstName IS NULL 
    AND NOT Alias2.LastName  IS NULL
   ) OR (
    Alias2.FamilyName = dbo.fnRemoveNonLetter(Table1.FamilyName)
    AND Alias2.Child1Name = dbo.fnRemoveNonLetter(Table1.Child1Name)
    AND NOT dbo.fnRemoveNonLetter(Table1.FamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.Child1Name) IS NULL
    AND NOT Alias2.Familyname IS NULL
    AND NOT Alias2.Child1Name IS NULL
   ) OR (
    Alias2.StepFamilyName = dbo.fnRemoveNonLetter(Table1.StepFamilyName)
    AND Alias2.StepFamilyNameChild1 = dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2)
    AND NOT Alias2.StepFamilyName IS NULL
    AND NOT Alias2.StepFamilyNameChild1 IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyName) IS NULL
    AND NOT dbo.fnRemoveNonLetter(Table1.StepFamilyNameChild2) IS NULL
   )  
 ) AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )

SQL-2005


SQL2008R2

:: EDIT :: Eseguita la query da una diversa istanza SQL2005, praticamente lo stesso piano di esecuzione di "buono". Non sono ancora sicuro di come le due versioni 2005 funzionino meglio sul server collegato 2008R2, rispetto alle istanze 2008R2 rispetto alle istanze 2008R2.

Anche se non nego che il codice possa usare un po 'di lavoro, se il problema fosse il codice, non vedrei gli stessi piani di exec in tutte le mie prove? Indipendentemente dalla versione di SQL?

:: EDIT :: Ho applicato SP1 e CU3 a entrambe le istanze 2008R2, ancora nessun dado. Ho impostato specificamente la collocazione nel server collegato, senza dadi. Ho impostato specificamente le autorizzazioni del mio utente accs per essere amministratore di sistema su entrambi i casi, senza dadi. Ho anche ricordato i miei interni SQL Server 2008 e la risoluzione dei problemi, vedremo se riesco a rintracciarli in qualche modo.

Grazie a tutti per l'aiuto e i suggerimenti.

:: EDIT :: Ho apportato varie modifiche alle autorizzazioni al server collegato. Ho usato accessi SQL, accessi al dominio, ho utenti impersonati, ho usato l'opzione "sia fatta usando questo contesto di sicurezza". Ho creato utenti su entrambi i lati del server collegato che dispongono dei diritti di amministratore di sistema sul server. Non ho più idee.

Vorrei ancora sapere perché SQL2005 sta eseguendo la query in modo così drammaticamente diverso da SQL2008R2. Se la query fosse sbagliata, vedrei il tempo di esecuzione di 4+ ore su SQL2005 e SQL2008R2.

Risposte:


5

Vorrei che tu rielaborassi la domanda.

Hai problemi di sargability e stai persino usando chiamate di funzioni scalari, che danneggeranno anche la query. Potresti voler creare una colonna calcolata FullName su Table2 e inserirvi un indice, assicurandoti che il tuo indice INCLUDE FirstName e LastName. Dovresti anche aggiungere indici che aiutino l'altro

Inoltre, crea una funzione inline con valori di tabella per eseguire la tua funzionalità "RemoveNonLetter" e rielabora la tua query per usarla, probabilmente usando APPLY come ho fatto qui.

E sicuramente controlla quel bug a cui fa riferimento la risposta di Paul .

INSERT INTO Table1_GroupLock (iGroupID, dLockedDate)
SELECT 
 Table1.iGroupID,
 GETDATE()
FROM Table1
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FullName)) AS fn (FullName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.FamilyName)) AS famn (FamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.Child1Name)) AS c1n (Child1Name)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyName)) AS sfn (StepFamilyName)
OUTER APPLY (SELECT NonLettersRemoved FROM dbo.ifnRemoveNonLetter(Table1.StepFamilyNameChild2)) AS sfnc2 (StepFamilyNameChild2)
WHERE 
 NOT EXISTS (
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FullName = fn.FullName
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.FamilyName = famn.FamilyName AND Alias2.Child1Name = c1n.Child1Name
  UNION ALL
  SELECT 1
  FROM LinkedServer.Database.Table2 Alias2
  WHERE Alias2.StepFamilyName = sfn.StepFamilyName AND Alias2.StepFamilyNameChild1 = sfnc2.StepFamilyNameChild2
 ) 
 AND NOT EXISTS (
  SELECT 1
  FROM Table3
  INNER JOIN Table4
   ON Table4.FirstNameType = Table3.FirstNameType 
  INNER JOIN table5
   ON table5.LastNameType = Table3.LastNameType 
  WHERE 
   Table3.iGroupID = Table1.iGroupID
   AND Table3.bIsClosed = 0
   AND Table4.sNameTypeConstant = 'new_lastname'
   AND table5.sFirstNameConstant = 'new_firstname'
 )
;

6

Aggiungendo alle risposte precedenti, il motivo della regressione del piano potrebbe essere dovuto a un bug di stima della cardinalità noto quando il piano include un Anti Semi Join. Vedi KB 2222998

Supponendo che il piano del 2005 abbia prodotto prestazioni accettabili, potresti scoprire che portare il server a una versione che include quella correzione (e abilitare TF4199 per attivarla) ti riporterà al piano "buono".

Detto questo, ci sono molte altre opportunità per migliorare quella query, quindi potrebbe essere un buon momento per concentrarsi sul farlo.


5

Suggerirei che i dati remoti vengano inviati in spool localmente a causa di uno dei

  1. Le impostazioni del server collegato (come le regole di confronto) non sono le stesse
  2. Le regole di confronto locali non sono uguali a quelle remote, nonostante le impostazioni del server collegato
  3. La query non può essere eseguita correttamente in remoto a causa delle autorizzazioni

Per il punto 1, vedere sp_serveroption
E per il punto 2, ma controllare anche le regole di confronto server / db.

Per il punto 3, vedi questi da Linchi Shea:

Stai chiedendo a SQL Server di elaborare tutti i dati localmente, secondo la mia risposta qui: implicazioni sulle prestazioni dell'uso di OPENQUERY in una vista

modificare

Al secondo sguardo, vedo 2 chiamate remote sul piano "buono" piuttosto che uno. Ciò conferma ciò che dico qui


Ci scusiamo per il lungo ritardo. 1: ho controllato le impostazioni del server collegato, sono le stesse 2: ho anche controllato e impostato in modo implicito il confronto delle proprietà del server collegato sul server remoto. 3: Il contesto di sicurezza a cui sto ancora lavorando per eseguire i test A / B. Sto ancora soffocando sulla logica dietro i piani esecutivi drasticamente diversi. Dal server R2 al server R2 esegue solo la selezione (inserendo oltre 150.000 righe), quindi eseguendo i join. Dove dal 2005 a R2 sta facendo le selezioni e si unisce sul server remoto. Il contesto di sicurezza per entrambi gli scenari è lo stesso.
RateControl

3

+1 su Prova a riscrivere il commento della query dal datagod.

Mi chiedo anche se stai incontrando un problema di autorizzazioni sul lato server collegato che porta a questo rallentamento. Ho scritto un blog su questo rallentamento del server collegato qualche tempo fa. Potrebbe valere la pena di verificare i permessi (è un server collegato a SQL? O è un altro DBMS? Se quest'ultimo, allora non otterrai comunque grandi statistiche)

SQL Server 2005 è ancora nell'ambiente di test per provare questa query ed escludere l'ambiente?

Hai ricostruito le statistiche dall'aggiornamento?


3

Ci sono così tanti problemi con questo confronto ... Non so da dove cominciare.

  1. Ottieni le specifiche esatte per le macchine di produzione e collaudo.

  2. Determinare i collegamenti di rete tra i vari server collegati in entrambi gli ambienti. Hanno la stessa velocità? I server si trovano uno accanto all'altro in entrambi gli ambienti?

  3. Esiste un modo per riscrivere la query per NON utilizzare i server collegati? Unire le tabelle tra i server ti rende vulnerabile alle modifiche della topologia e nella sua orribile lentezza nella maggior parte dei casi.

  4. L'uso di NOT e OR generalmente porta a scansioni di tabelle complete. Prova a riscrivere la query.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.