SQL Server 2014 Rallentamento improvviso / Nessun inserto / Non correlato a hardware o indice


8

Sto eseguendo un 350GBdatabase sul mio PC con circa 40 milioni di righe.

SQL Server 2014, Win7, AMD 8350 @ 4.8GHZ, 16 GB di RAM e un SSD da 500 GB (il database è ospitato sul proprio SSD da 500 GB, con una velocità di lettura / scrittura di 500 MB / 500 MB).

Il database non viene aggiornato, lo sto solo analizzando / leggendo. Con la creazione di alcuni indexes, qualsiasi join, count(*)ecc., Richiede meno di 1 minuto, il che è ok per i miei scopi. Ho eseguito alcune query (dopo aver eseguito una query di join singolo, 40-50 volte, diventa lenta) sui dati e ora le chiamate che hanno richiesto 1 minuto, sono ancora in esecuzione 20 minuti dopo.

Tengo d'occhio le risorse di sistema e posso vedere il SSDkick-in all'avvio della query, che legge per 20-30 secondi, quindi legge 121kB/secondper i successivi 20 minuti. Questo non è un problema alla CPU o al disco. Sono limitato con la mia quantità di RAM, tuttavia le chiamate vengono eseguite correttamente quando ho caricato il database per la prima volta, ora, non viene eseguito nulla, 25 minuti dopo.

In effetti non riesco più a interrogare il database, qualsiasi chiamata richiede troppo tempo anche SELECTun'istruzione di base . Ho provato a ricostruire gli indici e ad aggiornare le statistiche, ma nessuna differenza.

Non ho molta esperienza su questo, quindi è del tutto possibile che la mia query SQL sia errata, nel qual caso mi aspetto un errore o che finisca l'esecuzione con 0 risultati, ma nessuno dei due si verifica.

Quello che sto cercando di fare è contare tutte le istanze di un 'TypeID', nei 5 secondi precedenti un tempo basato sulla tabella ACALLS.

SELECT ACALLS.StartTime, ACALLS.Time, ACALLS.ServerIP, ACALLS.SRVR,   ACALLS.calls, ACALLS.TOKEN, COUNT(TypeID) as ExecRate
FROM ACALLS
INNER JOIN MAINVIEW ON 
MainView.TimeStamp BETWEEN ACALLS.StartTime and DATEADD(ss,-5,ACALLS.StartTime)

WHERE DATEPART(hour,MainView.TimeStamp) BETWEEN 10 and 13 and 
CAST(MainView.TimeStamp as date) = '2015-12-09' and
MainView.TypeID = '123456789'
GROUP BY Acalls.STartTime, ACALLs.TIME, ServerIp,SRVR, ACALLS.CALLS, ACALLS.TOKEN
ORDER BY Acalls.StartTime

Dopo aver eseguito "Who is Running", inserisci qui la descrizione dell'immagine inserisci qui la descrizione dell'immagine


Sospetto che ciò abbia a che fare con le statistiche sulle tabelle e i tipi di elaborazione effettuata per i join. È necessario esaminare i piani di esecuzione delle query: i join di loop nidificati possono essere un segnale di problemi.
Gordon Linoff,

Hai provato CON RECOMPILE?

3
Pubblica un piano di esecuzione effettivo di una query sorprendentemente lenta. Più semplice è la query, meglio è.
usr

1
Hai aggiornato le statistiche su tutte le tabelle? Hai ricostruito tutti gli indici? Informazioni su sp_whoisactive: link
TT.

2
Quelle statistiche di attesa mostrano molto IO ma non sappiamo quale percentuale della query sia IO e che cos'è la CPU. Eseguire i test che ho raccomandato come post i risultati.
usr

Risposte:


2

Hai una query non SARGable - anche se hai buoni indici, non li stai usando con quella query.

Innanzitutto, una reazione istintiva a pageiolatch_sh sta leggendo le pagine dal disco nel buffer; non hai abbastanza RAM per i dati che sta cercando di estrarre.

In secondo luogo, è necessario esaminare il piano di esecuzione e il suo utilizzo degli indici, o la loro mancanza.

Smetti di usare le funzioni nei tuoi join e in WHERE e ottieni solo i dati di cui hai assolutamente bisogno per iniziare.

  • "TRA ACALLS.StartTime e DATEADD (ss, -5, ACALLS.StartTime)" - sbarazzati di quel DATEADD tra BETWEEN.

    • Se si tratta di un database di report di sola lettura, quindi creare una tabella di report con solo i dati necessari e quindi inserire gli indici composti su di esso come richiesto. Utilizzalo per ottenere le chiavi primarie / altre chiavi univoche delle righe ACALLS che ti servono, quindi ottieni il resto dei dati ACALLS in un secondo momento.
  • DOVE PARTITO (ora, MainView.TimeStamp) TRA 10 e 13 e CAST (MainView.TimeStamp come data) = '2015-12-09'

    • stessa cosa - sbarazzarsi del CAST - cambiare '2015-12-09' in uno o due @parametri del giusto tipo di dati per MainView.TimeStamp> = @StartTimestamp AND MainView.TimeStamp <@EndTimestamp

    • e sbarazzarsi di quel DATEPART limitando @StartTimestamp e @EndTimestamp per includere anche i criteri delle ore.

Forse caricare una tabella #temp con solo le chiavi primarie / uniche delle righe che soddisfano tali criteri MainView prima del join.

Hmm ... inoltre, se Mainview è una vista complessa, vai direttamente alle tabelle di base per caricare quella tabella #temp

Non dimenticare di usare Profiler per controllare e vedere se aggiungere indici (composti se necessario) su #temp o altra tabella di staging è un guadagno netto o una perdita netta :).


1

creare un indice composito non cluster su mainview (typeid, timestamp).

cambia il tuo "dove" in mainview in modo da non utilizzare una funzione rispetto alle colonne mainview. ciò potrebbe richiedere di precalcolare questi valori come variabili prima di eseguire la query se è necessario che siano più dinamici.

WHERE MainView.TimeStamp BETWEEN '2015-12-09 10:00' and '2015-12-09 13:00'

creare un indice non cluster su ACALLS.StartTime.

cambia il join in ACALLS per essere

WHERE ACALLS.StartTime BETWEEN DATEADD(ss,-5,MainView.TimeStamp) AND MainView.TimeStamp

dalla mia comprensione, questo gestirà la tua logica e si unirà a prestazioni abbastanza elevate e ti allontanerà dall'IO.

la mia migliore ipotesi su ciò che stai incontrando è che i tuoi dati vengono scaricati dalla cache e / o tempdb si riversano sul disco di tanto in tanto, quindi la soluzione migliore che ho trovato in genere è scrivere le query meglio solo limitare l'utilizzo di tempdb e memoria e i problemi sottostanti scompaiono.

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.