none
Indagare problemi di performance non essendo però sysadmin su SS2008 RRS feed

  • Domanda

  •  

    Ciao a tutti,
    esiste una query, un vista di sistema o altro che posso lanciare per indagare come mai quando eseguo una semplice SELECT su di una tabella di un DB in Produzione ci mette tempi biblici (solo in questi giorni, prima funzionava abbastanza velocemente).
    Premetto che non sono sysadmin su questo database.
    Vorrei solo capire come mai ci sono questi problemi di performance.
    Il DB è SQL Server 2008 (10.50.1600).

    Grazie

    Luigi

     

    PS
    Piccola aggiunta.
    Dopo aver eseguito un'altra volta la Select, ed aver aspettato decine di minuti, mi esce:

    An error occurred while executing batch. Error message is: Generata eccezione di tipo 'System.OutOfMemoryException'.

     

    martedì 12 aprile 2011 12:23

Risposte

Tutte le risposte

  • esiste una query, un vista di sistema o altro che posso lanciare per indagare come mai quando eseguo una semplice SELECT su di una tabella di un DB in Produzione ci mette tempi biblici (solo in questi giorni, prima funzionava abbastanza velocemente).

    Ciao Luigi,

    La prima cosa da fare è analizzare il piano di esecuzione della query in modo da determinare con precisione quali sono gli step che impiegano più tempo o che restituiscono troppe righe rispetto a quanto preventivato.

    Spesso è sufficiente riuscrivere la query in modo più efficiente oppure intervenire sugli indici o le statistiche per velocizzare di diversi ordini di grandezza i tempi di esecuzione.

    Ciao!


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    martedì 12 aprile 2011 18:42
    Moderatore
  • Ciao Lorenzo,
    in realtà il problema, penso, sia sul server fisico, più che un problema sulla query.
    E' sempre stata eseguita in pochi secondi, mentre oggi ci ha messo ben 15 minuti per restituirmi 12 record!
    E poi, in un'altra prova, mi è uscito il problema di SystemOutOfMemory Exception.

    Luigi

    martedì 12 aprile 2011 19:19
  • Ciao Luigi,

    come giustamente dice Lorenzo, l'analisi del piano di esecuzione ti può far capire dov'è il problema.

    OutOfMemoryException è causato solitamente da una query troppo complessa. C'è da capire SE esiste un altro modo per scrivere la stessa queryoppure SE cambiando l'approccio, ad esempio limitando i JOIN, e/o includendo nella query solo i campi che ti servono. 

    Ad esempio se trovi un TABLE SCAN avrai sempre performance scadenti su quella tabella in cui questo avviene. Un po migliori sono INDEX SCAN, l'ideale è sempre un INDEX SEEK. IL piano di esecuzione ti può fornire indicazioni su quali sono le aree della tua query che sollecitano di più il server e che provocano lentezza e complessità di esecuzione - che può potenzilamente anche allocare grossi quantitativi di memoria e al limite portare all'OutOfMemoryException.

    Per curiosità puoi postare la query in questione? Magari può venir in mente qualcosa in più.

    Thanks

    Ciao,

     


    Adriano
    martedì 12 aprile 2011 19:24
  • in realtà il problema, penso, sia sul server fisico, più che un problema sulla query.
    E' sempre stata eseguita in pochi secondi, mentre oggi ci ha messo ben 15 minuti per restituirmi 12 record!
    E poi, in un'altra prova, mi è uscito il problema di SystemOutOfMemory Exception.

    Questo mi porta a pensare ad un pessimo piano di esecuzione (dovuto ad esempio a statistiche non aggiornate o indici molto frammentati) che è assolutamente indipendente dal numero di righe restituite.

    Per eventuali errori HW puoi dare un'occhiata agli eventi di sistema (in particolare i system log).

    Ciao!


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    martedì 12 aprile 2011 19:25
    Moderatore
  • @Adriano

    La query è veramente semplice, del tipo:

    SELECT * FROM MiaTabella
    WHERE Campo1 <> 5

    La tabella è si corposa (circa un milione di record), ma nei giorni precedenti veniva sempre eseguita in una manciata di minuti.

     

    @Lorenzo

    Dovrei chiedere ai DBA o ai sistemisti di controllare l'Event Viewer?
    Ma questo non dovrebbero già saperlo loro (in teoria)?
    Io purtroppo non ho accesso diretto al server, e non posso fare controlli mirati.

    Luigi

    mercoledì 13 aprile 2011 06:57
  • @Adriano

    La query è veramente semplice, del tipo:

    SELECT * FROM MiaTabella
    WHERE Campo1 <> 5

    La tabella è si corposa (circa un milione di record), ma nei giorni precedenti veniva sempre eseguita in una manciata di minuti.

     

    @Lorenzo

    Dovrei chiedere ai DBA o ai sistemisti di controllare l'Event Viewer?
    Ma questo non dovrebbero già saperlo loro (in teoria)?
    Io purtroppo non ho accesso diretto al server, e non posso fare controlli mirati.

    Luigi

    La colonna Campo1 è indicizzata? L'indice è deframmentato? Ti serve veramente restituire tutte le colonne della tabelle oppure puoi specificarne un sottoinsieme?

    Per quanto riguarda i tuoi sistemnisti/DBA dovresti chiedere a loro, io di certo non lo so :-)

    Ciao!


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    mercoledì 13 aprile 2011 07:19
    Moderatore
  • Sì il Campo1 è indicizzato. Come posso controllare però se è troppo deframmentato?

    L

    mercoledì 13 aprile 2011 07:21
  • Questa tabella è sempre stata di questa dimensione, oppure è cambiata frequentemente nell'ultimo periodo ?

    E' possibile che se la tua query prende un set AMPIO di record, SQL Server cambi l'approccio del piano di esecuzione, quindi se tu confrontassi il piano precedente con questo ultimo troveresti delle differenze.

    Quante righe ti aspetti che debbano venir ritornate? 1% delle righe, 50% delle righe? SQL Server sceglie l'approccio in base a questi parametri (e non solo).

    Poi ti devi chiedere: mi servono TUTTE queste informazioni, oppure mi bastano 3-4 campi? Select A, B, C, D ? Se ti bastano certi campi probabilmente avere un Indice Coverered su questi campi migliora le performances.

    Tabelle con milioni di records solitamente vengono gestite al meglio con il partitioning oppure hai spazio di miglioramento sposti i campi BINARY/NTEXT esternamente. Inoltre una corretta normalizzazione aiuta SQL Server a comportarsi meglio in queste situazioni.

    Ad ogni modo, prova ad eseguire "sp_updatestats" per ri-eseguire l'aggiornamento delle statistiche del tuo db/tabella.

    Puoi provare anceh con un Maintenance Plan a ricostruire gli indici,oppure fai un Rebuild Index (di tutti) della tua tabella.

    HTH,

    Ciao,


    Adriano
    mercoledì 13 aprile 2011 07:24
  • Sì il Campo1 è indicizzato. Come posso controllare però se è troppo deframmentato?

    Utilizza il classico DBCC SHOWCONTIG oppure la dynamic management view sys.dm_db_index_physical_stats.

    Ciao!


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    mercoledì 13 aprile 2011 07:25
    Moderatore
  • Questo è quello che mi viene restituito con la DBCC:

    DBCC SHOWCONTIG scanning 'T_Integrazione' table...
    Table: 'T_Integrazione' (852458361); index ID: 1, database ID: 12
    TABLE level scan performed.
    - Pages Scanned................................: 7176
    - Extents Scanned..............................: 908
    - Extent Switches..............................: 976
    - Avg. Pages per Extent........................: 7.9
    - Scan Density [Best Count:Actual Count].......: 91.81% [897:977]
    - Logical Scan Fragmentation ..................: 0.99%
    - Extent Scan Fragmentation ...................: 99.67%
    - Avg. Bytes Free per Page.....................: 82.1
    - Avg. Page Density (full).....................: 98.99%
    DBCC execution completed. If DBCC printed error messages, contact your system administrator.


    Come ti sembra?

    Luigi

    mercoledì 13 aprile 2011 07:35
  • DBCC SHOWCONTIG scanning 'T_Integrazione' table...
    Table: 'T_Integrazione' (852458361); index ID: 1, database ID: 12
    TABLE level scan performed.
    - Pages Scanned................................: 7176
    - Extents Scanned..............................: 908
    - Extent Switches..............................: 976
    - Avg. Pages per Extent........................: 7.9
    - Scan Density [Best Count:Actual Count].......: 91.81% [897:977]
    - Logical Scan Fragmentation ..................: 0.99%
    - Extent Scan Fragmentation ...................: 99.67%
    - Avg. Bytes Free per Page.....................: 82.1
    - Avg. Page Density (full).....................: 98.99%
    DBCC execution completed. If DBCC printed error messages, contact your system administrator.

    Come ti sembra?

    Hai un indice clustered (definito solo su questa colonna o anche su altre?) con una elevata frammentazione a livello di extent. Dato che la tabella è piuttosto corposa a livello di righe, individua una finestra temporale per eseguire la ricostruzione dell'indice clustered.

    Ad ogni modo non abbiamo informazioni sufficienti per stabilire se questa "cura" porterà ad un miglioramento nell'esecuzione della query.

    Ciao!


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    mercoledì 13 aprile 2011 07:42
    Moderatore
  • Rettifico, non c'è un indice sul campo che pensavo.
    Quindi la struttura della tabella in TEST è diversa da quella in Produzione.
    Questo è lo script che crea la tabella in Prod.

     

    /****** Object:  Table [app].[T_Integrazione]    Script Date: 04/13/2011 09:55:30 ******/
    SET ANSI_NULLS ON
    GO

    SET QUOTED_IDENTIFIER ON
    GO

    SET ANSI_PADDING ON
    GO

    CREATE TABLE [app].[T_Integrazione](
     [IntegrazioneEsportazione_ID] [int] IDENTITY(1,1) NOT NULL,
     [NomeFile] [varchar](100) NULL,
     [DirectoryTarget] [varchar](500) NULL,
     [IntegrazioneTipoCaricamento_ID] [int] NULL,
     [ContenutoFile] [text] NULL,
     [DataInserimentoInCoda] [datetime] NULL,
     [DataInvioBiztalk] [datetime] NULL,
     [DataEsportazione] [datetime] NULL,
     [IntegrazioneStatoCaricamento_ID] [int] NULL,
     [Guid] [varchar](50) NULL,
     [Accorpato_ID] [int] NULL,
     [Forzatura] [int] NULL,
     [UtenteForzatura_ID] [int] NULL,
     [DataOraForzatura] [datetime] NULL,
     CONSTRAINT [PK_T_IntegrazioneEsportazione] PRIMARY KEY CLUSTERED
    (
     [IntegrazioneEsportazione_ID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

    GO

    SET ANSI_PADDING OFF
    GO

    ALTER TABLE [app].[T_Integrazione]  WITH CHECK ADD  CONSTRAINT [FK_T_IntegrazioneCodaEsportazione_T_IntegrazioneStatoCaricamento] FOREIGN KEY([Forzatura])
    REFERENCES [app].[T_IntegrazioneStatoCaricamento] ([IntegrazioneStatoCaricamento_ID])
    GO

    ALTER TABLE [app].[T_Integrazione] CHECK CONSTRAINT [FK_T_IntegrazioneCodaEsportazione_T_IntegrazioneStatoCaricamento]
    GO

    ALTER TABLE [app].[T_Integrazione]  WITH CHECK ADD  CONSTRAINT [FK_T_IntegrazioneCodaEsportazione_T_Utenti] FOREIGN KEY([UtenteForzatura_ID])
    REFERENCES [app].[T_Utenti] ([Utenti_ID])
    GO

    ALTER TABLE [app].[T_Integrazione] CHECK CONSTRAINT [FK_T_IntegrazioneCodaEsportazione_T_Utenti]
    GO

    ALTER TABLE [app].[T_Integrazione]  WITH CHECK ADD  CONSTRAINT [FK_T_IntegrazioneEsportazione_T_IntegrazioneStatoCaricamento] FOREIGN KEY([IntegrazioneStatoCaricamento_ID])
    REFERENCES [app].[T_IntegrazioneStatoCaricamento] ([IntegrazioneStatoCaricamento_ID])
    GO

    ALTER TABLE [app].[T_Integrazione] CHECK CONSTRAINT [FK_T_IntegrazioneEsportazione_T_IntegrazioneStatoCaricamento]
    GO

    ALTER TABLE [app].[T_Integrazione]  WITH NOCHECK ADD  CONSTRAINT [FK_T_IntegrazioneEsportazione_T_IntegrazioneTipoCaricamento] FOREIGN KEY([IntegrazioneTipoCaricamento_ID])
    REFERENCES [app].[T_IntegrazioneTipoCaricamento] ([IntegrazioneTipoCaricamento])
    GO

    ALTER TABLE [app].[T_Integrazione] CHECK CONSTRAINT [FK_T_IntegrazioneEsportazione_T_IntegrazioneTipoCaricamento]
    GO

    ALTER TABLE [app].[T_Integrazione] ADD  CONSTRAINT [PK_T_IntegrazioneEsportazione] PRIMARY KEY CLUSTERED
    (
     [IntegrazioneEsportazione_ID] ASC
    )WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
    GO

     

    Luigi

    mercoledì 13 aprile 2011 07:54
  • Rettifico, non c'è un indice sul campo che pensavo.
    Quindi la struttura della tabella in TEST è diversa da quella in Produzione.
    1. Tu stai lavorando in produzione o in test?
    2. Qual è la struttura in ambiente di test?
    3. Qual è la tua query?

    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    mercoledì 13 aprile 2011 08:00
    Moderatore

  • Io utilizzo il Management Studio sul mio pc collegandomi al database in Produzione.

    La query che eseguo è:

    SELECT * FROM app.T_integrazione
    WHERE IntegrazioneStatoCaricamento_ID <> 5


    L

    mercoledì 13 aprile 2011 08:05
  • Io utilizzo il Management Studio sul mio pc collegandomi al database in Produzione.

    La query che eseguo è:

    SELECT * FROM app.T_integrazione
    WHERE IntegrazioneStatoCaricamento_ID <> 5

    1. Come già indicato individua una finestra temporale per eseguire la ricostruzione dell'indice clustered;
    2. Riduci il numero di colonne restituito dal comando di SELECT. Se sono 2 o 3  definisci un indice non clustered sulla colonna IntegrazioneStatoCaricamento_ID, col2, col3 in modo da coprire la query.
    3. Se le colonne sono molte definisci un indice non clustered sulla colonna IntegrazioneStatoCaricamento_ID.

    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    mercoledì 13 aprile 2011 08:11
    Moderatore
  • Probabilmente è un problema di eccessivo uso della memoria del server.
    Pur avendo 8 GB di Ram, ne risultano ben 7 in uso (attraverso il performance monitor).

    Luigi

    mercoledì 13 aprile 2011 08:31
  • Probabilmente è un problema di eccessivo uso della memoria del server.
    Pur avendo 8 GB di Ram, ne risultano ben 7 in uso (attraverso il performance monitor).

    Tutti i DBMS (e SQL Server non è una eccezione) utilizzano tutta la RAM disponibile in modo da minimizzare l'I/O su disco, quindi il comportamento è del tutto normale.

    Per verificare se la RAM è sufficiente, verifica con il Performance Monitor che il counter Buffer cache hit ratio sia sempre sopra il 90-95%.

    Ciao!


    Lorenzo Benaglia
    Microsoft MVP - SQL Server
    http://blogs.dotnethell.it/lorenzo
    http://social.technet.microsoft.com/Forums/it-IT/sqlserverit
    • Contrassegnato come risposta Ciupaz mercoledì 13 aprile 2011 10:08
    mercoledì 13 aprile 2011 08:39
    Moderatore
  • Grazie Lorenzo,
    direi che per ora è sufficiente.

    Luigi

    mercoledì 13 aprile 2011 10:08
  • E' il client a non avere memoria...
    lunedì 7 novembre 2011 13:37