Ho un problema con una query del database SQL che all'improvviso (ma regolarmente ogni tre settimane) diventa lento.SQL Server query improvvisamente lento
installazione è la seguente:
-
Express 2008 R2
- Il database ha una dimensione di 6 GB (file mdf
- Windows Server 2008 (non R2) a 64 bit, 8 GB di RAM
- SQL Server dimensioni)
- la tabella (
Orders
) la query è principalmente selezionando dal ha circa 24000 record, altri cinque tabelle unite piccole (100 record o meno) - la tabella
Orders
ha un 012.colonnaReport
che contiene dati binari (documenti PDF) con una dimensione media di circa 200 a 300 kB (ma può essere fino a 2 MB di tanto in tanto). Più del 90% di questi 24000 ordini ha questa colonna riempita, per gli altri èNULL
, vale a dire più del 90% delle dimensioni del database di 6 GB sono dati binari.
La query in questione ha la seguente struttura:
SELECT TOP (30) [Project2].[OrderID] AS [OrderID]
-- around 20 columns more
FROM (SELECT [Project2].[OrderID] AS [OrderID],
-- around 20 columns more
row_number() OVER (ORDER BY [Project2].[OrderID] ASC) AS [row_number]
FROM (SELECT [Filter1].[OrderID] AS [OrderID]
-- around 20 columns more
FROM (SELECT [Extent1].[OrderID] AS [OrderID]
-- around 20 columns more
FROM [dbo].[Orders] AS [Extent1]
INNER JOIN -- small table
LEFT OUTER JOIN -- small table
LEFT OUTER JOIN -- small table
LEFT OUTER JOIN -- small table
LEFT OUTER JOIN -- small table
WHERE ([Extent1].[Status] IS NOT NULL)
AND (4 = CAST([Extent1].[Status] AS int))
AND ([Extent1].[SomeDateTime] IS NULL)
AND ([Extent1].[Report] IS NULL)
) AS [Filter1]
OUTER APPLY (SELECT TOP (1) [Project1].[C1] AS [C1]
FROM (SELECT CAST([Extent7].[CreationDateTime] AS datetime2) AS [C1],
[Extent7].[CreationDateTime] AS [CreationDateTime]
FROM [dbo].[OtherTable] AS [Extent7]
WHERE [Filter1].[OrderID] = [Extent7].[OrderID]
) AS [Project1]
ORDER BY [Project1].[CreationDateTime] DESC
) AS [Limit1]
) AS [Project2]
) AS [Project2]
WHERE [Project2].[row_number] > 0
ORDER BY [Project2].[OrderID] ASC
Si è generato da una query LINQ to entità da Entity Framework. La query si verifica in alcune varianti che differiscono solo nel primo WHERE
clausola:
I cinque varianti
WHERE ([Extent1].[Status] IS NOT NULL) AND (X = CAST([Extent1].[Status] AS int))
X può essere tra
0
e4
. Queste domande non sono mai un problema.E le due varianti (*)
WHERE ([Extent1].[Status] IS NOT NULL) AND (4 = CAST([Extent1].[Status] AS int)) AND ([Extent1].[SomeDateTime] IS NULL) AND ([Extent1].[Report] IS NULL)
o
... IS NOT NULL...
nell'ultima riga. Ho il problema descritto di seguito solo con queste due domande.
Il "fenomeno" è:
- Le due interrogazioni (*) sono gestiti da 100 a 200 volte al giorno, 5 giorni alla settimana. Si esibiscono con meno di un secondo per circa tre settimane.
- Dopo tre settimane entrambe le query richiedono improvvisamente più di 60 secondi. (Questa volta aumenta in realtà con la crescente dimensione del database.) Gli utenti ottengono un errore (nella pagina Web, è un'app Web) a causa di un timeout. (Per impostazione predefinita, Entity Framework non sembra attendere più di 30 secondi per il risultato.)
- Se si incolla la query in SSMS e si esegue la query (in attesa dei 60 secondi) il risultato viene restituito correttamente e lo stesso successivo la query viene eseguita nuovamente in meno di un secondo.
- Dopo circa tre settimane lo stesso accade di nuovo (ma il tempo le piste della query sarà di 65 o 70 secondi, quindi)
Un ulteriore osservazione:
- Se ricomincio il processo di servizio di SQL Server nei momenti in cui la query è normale, l'utilizzo della memoria del processo aumenta lentamente. Raggiunge un limite di circa 1,5 GB (set di lavoro privato in Task Manager), passo dopo passo, entro circa una settimana.
- Se riavvio il processo del servizio SQL Server quando la query è improvvisamente lenta e si attiva nuovamente la query, è possibile controllare in Task Manager che il servizio carica quasi 1 GB in pochi secondi.
In qualche modo ho il sospetto che tutto il problema ha a che fare con la limitazione di memoria (1 GB) dell'edizione Express e la colonna varbinary(MAX)
anche se ho appena uso nella clausola WHERE
che controlla se il valore della colonna è NULL
o no NULL
. La colonna Report
non è una delle colonne selezionate.
Dato che io sono in esecuzione contro le limitazioni (10 GB file MDF dimensione) della Express Edition prossimo anno più recente sto prendendo in considerazione i cambiamenti in ogni caso:
- O spostare la colonna binaria ad un altro tavolo e memorizzare il contenuto dall'esterno via FILESTREAM, continuare ad usare l'Express Edition
- utilizzare uno dei "grandi" edizioni di SQL Server senza le limitazioni Express, mantenere la colonna binaria nella tabella
Orders
- fare entrambe le cose
Domanda: quale potrebbe essere il motivo per cui la query è improvvisamente lenta? Potrebbe uno dei cambiamenti che sto pianificando risolvere il problema o ci sono altre soluzioni?
Modifica
seguente suggerimento del bhamby nei commenti qui sotto ho impostato SET STATISTICS TIME ON
in SSMS prima di eseguire nuovamente la query. Quando la query è di nuovo lenta, ottengo un valore elevato per SQL Server parse and compile time
, vale a dire: CPU time = 27,3 sec
e Elapsed time = 81,9 sec
. Il tempo di esecuzione per la query è solo il tempo della CPU = 0,06 secondi e il tempo trascorso = 2,8 secondi. Eseguendo la query una seconda volta dopo questo tempo della CPU 0,06 sec e Tempo trascorso = 0,08 per l'analisi di SQL Server e il tempo di compilazione.
È possibile isolare qualsiasi processo che coincide con questo intervallo di 3 settimane? Sembra strano che qualcosa di diverso dalla concorrenza possa causare quel tipo di prestazioni incoerenti. –
@GoatCO: l'ho controllato più volte, ma non c'è concorrenza con altri processi. La frequenza non è * esattamente * 3 settimane, può essere alcuni giorni più o meno e può succedere al mattino o al pomeriggio. Quando accade non c'è né una CPU elevata né un carico di memoria sul server. E il problema non scompare mai da solo (cosa che mi aspetterei se qualche altro processo concorrente finisse). L'unico modo che ho trovato finora è eseguire la query una volta in SSMS. – Slauma
Ah è interessante. Se lo si esegue in SSMS di volta in volta, è possibile evitare del tutto il rallentamento o si verifica ancora? –