Come visualizzare la cronologia delle query in SQL Server Management Studio


159

La cronologia delle query è memorizzata in alcuni file di registro? Se sì, puoi dirmi come trovare la loro posizione? In caso contrario, puoi darmi qualche consiglio su come vederlo?


1
http://www.ssmstoolspack.com/ fornisce una finestra della cronologia se è quello che stai cercando.
TI

Risposte:


226

[Dal momento che questa domanda sarà probabilmente chiusa come duplicato.]

Se SQL Server non è stato riavviato (e il piano non è stato sfrattato, ecc.), Potresti essere in grado di trovare la query nella cache del piano.

SELECT t.[text]
FROM sys.dm_exec_cached_plans AS p
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
WHERE t.[text] LIKE N'%something unique about your query%';

Se hai perso il file a causa di un arresto anomalo di Management Studio, potresti trovare qui i file di ripristino:

C:\Users\<you>\Documents\SQL Server Management Studio\Backup Files\

Altrimenti dovrai utilizzare qualcos'altro per aiutarti a salvare la cronologia delle query, come il pacchetto di strumenti SSMS come indicato nella risposta di Ed Harper, sebbene non sia gratuito in SQL Server 2012+. Oppure puoi impostare una traccia leggera filtrata sul tuo login o nome host (ma per favore usa una traccia lato server, non Profiler, per questo).


Come ha commentato @ Nenad-Zivkovic, potrebbe essere utile partecipare sys.dm_exec_query_statse ordinare per last_execution_time:

SELECT t.[text], s.last_execution_time
FROM sys.dm_exec_cached_plans AS p
INNER JOIN sys.dm_exec_query_stats AS s
   ON p.plan_handle = s.plan_handle
CROSS APPLY sys.dm_exec_sql_text(p.plan_handle) AS t
WHERE t.[text] LIKE N'%something unique about your query%'
ORDER BY s.last_execution_time DESC;

9
Potrebbe anche aiutare a partecipare sys.dm_exec_query_statse cercare o ordinare dalast_execution_time
Nenad Zivkovic il

Non funziona con SQL Server 2000 e funziona con SQL Server 2005
Durai Amuthan.H

@Duraiamuthan Bene, la domanda si pone su Management Studio, quindi dovrebbe essere sicuro presumere 2005+. 2000 non aveva Management Studio, aveva Query Analyzer. Il 2000 è anche da molti anni senza supporto. Se vuoi risolvere questo problema per SQL Server 2000, dovresti probabilmente porre una nuova domanda taggata con quella versione specifica (se non esiste un duplicato, che non ho verificato).
Aaron Bertrand,

1
@AaronBertrand Il mio commento è complementare alla tua risposta. Aiuterà gli altri
Durai Amuthan.H,

3
@AaronBertrand Sei un dio tra gli uomini.
AnotherDeveloper

49

In ritardo, ma si spera utile poiché aggiunge più dettagli ...

Non è possibile visualizzare le query eseguite in SSMS per impostazione predefinita. Ci sono diverse opzioni però.

Leggere il registro delle transazioni: questa non è una cosa facile da fare perché è in formato proprietario. Tuttavia, se è necessario visualizzare le query eseguite storicamente (tranne SELEZIONA), questo è l'unico modo.

A tale scopo è possibile utilizzare strumenti di terze parti come ApexSQL Log e SQL Log Rescue (gratuito ma solo SQL 2000). Dai un'occhiata a questo thread per maggiori dettagli qui Explorer / Analyzer Log transazioni SQL Server

Profiler di SQL Server: più adatto se si desidera solo avviare il controllo e non si è interessati a ciò che è accaduto in precedenza. Assicurati di utilizzare i filtri per selezionare solo le transazioni necessarie. Altrimenti finirai con tonnellate di dati molto rapidamente.

Traccia di SQL Server: la soluzione migliore se si desidera acquisire tutti o la maggior parte dei comandi e tenerli nel file di traccia che può essere analizzato in un secondo momento.

Trigger: più adatti se si desidera acquisire DML (tranne selezionare) e archiviarli da qualche parte nel database


La creazione di un file di traccia in SQL Server Profiler ( msdn.microsoft.com/en-us/library/ms175047(v=sql.110).aspx ) utilizzando il modello standard è un buon modo per monitorare le istruzioni eseguite.
javiniar.leonard,


6

Come altri hanno già notato, è possibile utilizzare SQL Profiler, ma è anche possibile sfruttarne la funzionalità tramite le procedure memorizzate nel sistema sp_trace_ *. Ad esempio, questo frammento SQL (almeno nel 2000; penso che sia lo stesso per SQL 2008 ma dovrete ricontrollare) catch RPC:Completeded SQL:BatchCompletedeventi per tutte le query che richiedono più di 10 secondi per l'esecuzione e salvare l'output in un file di traccia che è possibile aprire nel profiler SQL in un secondo momento:

DECLARE @TraceID INT
DECLARE @ON BIT
DECLARE @RetVal INT
SET @ON = 1

exec @RetVal = sp_trace_create @TraceID OUTPUT, 2, N'Y:\TraceFile.trc'
print 'This trace is Trace ID = ' + CAST(@TraceID AS NVARCHAR)
print 'Return value = ' + CAST(@RetVal AS NVARCHAR)
-- 10 = RPC:Completed
exec sp_trace_setevent @TraceID, 10, 1, @ON     -- Textdata
exec sp_trace_setevent @TraceID, 10, 3, @ON     -- DatabaseID
exec sp_trace_setevent @TraceID, 10, 12, @ON        -- SPID
exec sp_trace_setevent @TraceID, 10, 13, @ON        -- Duration
exec sp_trace_setevent @TraceID, 10, 14, @ON        -- StartTime
exec sp_trace_setevent @TraceID, 10, 15, @ON        -- EndTime

-- 12 = SQL:BatchCompleted
exec sp_trace_setevent @TraceID, 12, 1, @ON     -- Textdata
exec sp_trace_setevent @TraceID, 12, 3, @ON     -- DatabaseID
exec sp_trace_setevent @TraceID, 12, 12, @ON        -- SPID
exec sp_trace_setevent @TraceID, 12, 13, @ON        -- Duration
exec sp_trace_setevent @TraceID, 12, 14, @ON        -- StartTime
exec sp_trace_setevent @TraceID, 12, 15, @ON        -- EndTime

-- Filter for duration [column 13] greater than [operation 2] 10 seconds (= 10,000ms)
declare @duration bigint
set @duration = 10000
exec sp_trace_setfilter @TraceID, 13, 0, 2, @duration

È possibile trovare l'ID per ogni evento di traccia, colonne, ecc. Nella documentazione online; basta cercare gli sproctr sp_trace_create , sp_trace_setevent e sp_trace_setfiler . È quindi possibile controllare la traccia come segue:

exec sp_trace_setstatus 15, 0       -- Stop the trace
exec sp_trace_setstatus 15, 1       -- Start the trace
exec sp_trace_setstatus 15, 2       -- Close the trace file and delete the trace settings

... dove '15' è l'ID di traccia (come riportato da sp_trace_create, che il primo script elimina sopra).

Puoi controllare per vedere quali tracce sono in esecuzione con:

select * from ::fn_trace_getinfo(default)

L'unica cosa che dirò con cautela : non so quanto carico questo metterà sul tuo sistema; ne aggiungerà un po ', ma quanto è grande quel "alcuni" probabilmente dipende da quanto è occupato il tuo server.


Codice utile. Ha funzionato solo per me quando ho rimosso l'estensione ".trc".
Steve Smith,

5

Il sistema non registra le query in quel modo. Se sai che vuoi farlo prima del tempo, puoi usare SQL Profiler per registrare ciò che sta arrivando e tenere traccia delle query durante il tempo in cui Profiler è in esecuzione.


5

Uso la query seguente per tracciare l'attività dell'applicazione su un server SQL in cui non è abilitato il profiler di traccia. Il metodo utilizza Query Store (SQL Server 2016+) invece dei DMV. Ciò offre una migliore capacità di esaminare dati storici e ricerche più veloci. È molto efficiente acquisire query di breve durata che non possono essere acquisite da sp_who / sp_whoisactive.

/* Adjust script to your needs.
    Run full script (F5) -> Interact with UI -> Run full script again (F5)
    Output will contain the queries completed in that timeframe.
*/

/* Requires Query Store to be enabled:
    ALTER DATABASE <db> SET QUERY_STORE = ON
    ALTER DATABASE <db> SET QUERY_STORE (OPERATION_MODE = READ_WRITE, MAX_STORAGE_SIZE_MB = 100000)
*/

USE <db> /* Select your DB */

IF OBJECT_ID('tempdb..#lastendtime') IS NULL
    SELECT GETUTCDATE() AS dt INTO #lastendtime
ELSE IF NOT EXISTS (SELECT * FROM #lastendtime)
    INSERT INTO #lastendtime VALUES (GETUTCDATE()) 

;WITH T AS (
SELECT 
    DB_NAME() AS DBName
    , s.name + '.' + o.name AS ObjectName
    , qt.query_sql_text
    , rs.runtime_stats_id
    , p.query_id
    , p.plan_id
    , CAST(p.last_execution_time AS DATETIME) AS last_execution_time
    , CASE WHEN p.last_execution_time > #lastendtime.dt THEN 'X' ELSE '' END AS New
    , CAST(rs.last_duration / 1.0e6 AS DECIMAL(9,3)) last_duration_s
    , rs.count_executions
    , rs.last_rowcount
    , rs.last_logical_io_reads
    , rs.last_physical_io_reads
    , q.query_parameterization_type_desc
FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY plan_id, runtime_stats_id ORDER BY runtime_stats_id DESC) AS recent_stats_in_current_priod
    FROM sys.query_store_runtime_stats 
    ) AS rs
INNER JOIN sys.query_store_runtime_stats_interval AS rsi ON rsi.runtime_stats_interval_id = rs.runtime_stats_interval_id
INNER JOIN sys.query_store_plan AS p ON p.plan_id = rs.plan_id
INNER JOIN sys.query_store_query AS q ON q.query_id = p.query_id
INNER JOIN sys.query_store_query_text AS qt ON qt.query_text_id = q.query_text_id
LEFT OUTER JOIN sys.objects AS o ON o.object_id = q.object_id
LEFT OUTER JOIN sys.schemas AS s ON s.schema_id = o.schema_id
CROSS APPLY #lastendtime
WHERE rsi.start_time <= GETUTCDATE() AND GETUTCDATE() < rsi.end_time
    AND recent_stats_in_current_priod = 1
    /* Adjust your filters: */
    -- AND (s.name IN ('<myschema>') OR s.name IS NULL)
UNION
SELECT NULL,NULL,NULL,NULL,NULL,NULL,dt,NULL,NULL,NULL,NULL,NULL,NULL, NULL
FROM #lastendtime
)
SELECT * FROM T
WHERE T.query_sql_text IS NULL OR T.query_sql_text NOT LIKE '%#lastendtime%' -- do not show myself
ORDER BY last_execution_time DESC

TRUNCATE TABLE #lastendtime
INSERT INTO #lastendtime VALUES (GETUTCDATE()) 

4
SELECT deqs.last_execution_time AS [Time], dest.text AS [Query], dest.*
FROM sys.dm_exec_query_stats AS deqs
CROSS APPLY sys.dm_exec_sql_text(deqs.sql_handle) AS dest
WHERE dest.dbid = DB_ID('msdb')
ORDER BY deqs.last_execution_time DESC

Questo dovrebbe mostrare l'ora e la data di esecuzione di una query



3

La cronologia delle query può essere visualizzata utilizzando le viste di sistema:

  1. sys.dm_exec_query_stats
  2. sys.dm_exec_sql_text
  3. sys.dm_exec_query_plan

Ad esempio, utilizzando la seguente query:

select  top(100)
        creation_time,
        last_execution_time,
        execution_count,
        total_worker_time/1000 as CPU,
        convert(money, (total_worker_time))/(execution_count*1000)as [AvgCPUTime],
        qs.total_elapsed_time/1000 as TotDuration,
        convert(money, (qs.total_elapsed_time))/(execution_count*1000)as [AvgDur],
        total_logical_reads as [Reads],
        total_logical_writes as [Writes],
        total_logical_reads+total_logical_writes as [AggIO],
        convert(money, (total_logical_reads+total_logical_writes)/(execution_count + 0.0)) as [AvgIO],
        [sql_handle],
        plan_handle,
        statement_start_offset,
        statement_end_offset,
        plan_generation_num,
        total_physical_reads,
        convert(money, total_physical_reads/(execution_count + 0.0)) as [AvgIOPhysicalReads],
        convert(money, total_logical_reads/(execution_count + 0.0)) as [AvgIOLogicalReads],
        convert(money, total_logical_writes/(execution_count + 0.0)) as [AvgIOLogicalWrites],
        query_hash,
        query_plan_hash,
        total_rows,
        convert(money, total_rows/(execution_count + 0.0)) as [AvgRows],
        total_dop,
        convert(money, total_dop/(execution_count + 0.0)) as [AvgDop],
        total_grant_kb,
        convert(money, total_grant_kb/(execution_count + 0.0)) as [AvgGrantKb],
        total_used_grant_kb,
        convert(money, total_used_grant_kb/(execution_count + 0.0)) as [AvgUsedGrantKb],
        total_ideal_grant_kb,
        convert(money, total_ideal_grant_kb/(execution_count + 0.0)) as [AvgIdealGrantKb],
        total_reserved_threads,
        convert(money, total_reserved_threads/(execution_count + 0.0)) as [AvgReservedThreads],
        total_used_threads,
        convert(money, total_used_threads/(execution_count + 0.0)) as [AvgUsedThreads],
        case 
            when sql_handle IS NULL then ' '
            else(substring(st.text,(qs.statement_start_offset+2)/2,(
                case
                    when qs.statement_end_offset =-1 then len(convert(nvarchar(MAX),st.text))*2      
                    else qs.statement_end_offset    
                end - qs.statement_start_offset)/2  ))
        end as query_text,
        db_name(st.dbid) as database_name,
        object_schema_name(st.objectid, st.dbid)+'.'+object_name(st.objectid, st.dbid) as [object_name],
        sp.[query_plan]
from sys.dm_exec_query_stats as qs with(readuncommitted)
cross apply sys.dm_exec_sql_text(qs.[sql_handle]) as st
cross apply sys.dm_exec_query_plan(qs.[plan_handle]) as sp
WHERE st.[text] LIKE '%query%'

Le query in esecuzione correnti possono essere visualizzate utilizzando il seguente script:

select ES.[session_id]
      ,ER.[blocking_session_id]
      ,ER.[request_id]
      ,ER.[start_time]
      ,DateDiff(second, ER.[start_time], GetDate()) as [date_diffSec]
      , COALESCE(
                    CAST(NULLIF(ER.[total_elapsed_time] / 1000, 0) as BIGINT)
                   ,CASE WHEN (ES.[status] <> 'running' and isnull(ER.[status], '')  <> 'running') 
                            THEN  DATEDIFF(ss,0,getdate() - nullif(ES.[last_request_end_time], '1900-01-01T00:00:00.000'))
                    END
                ) as [total_time, sec]
      , CAST(NULLIF((CAST(ER.[total_elapsed_time] as BIGINT) - CAST(ER.[wait_time] AS BIGINT)) / 1000, 0 ) as bigint) as [work_time, sec]
      , CASE WHEN (ER.[status] <> 'running' AND ISNULL(ER.[status],'') <> 'running') 
                THEN  DATEDIFF(ss,0,getdate() - nullif(ES.[last_request_end_time], '1900-01-01T00:00:00.000'))
        END as [sleep_time, sec] --Время сна в сек
      , NULLIF( CAST((ER.[logical_reads] + ER.[writes]) * 8 / 1024 as numeric(38,2)), 0) as [IO, MB]
      , CASE  ER.transaction_isolation_level
        WHEN 0 THEN 'Unspecified'
        WHEN 1 THEN 'ReadUncommited'
        WHEN 2 THEN 'ReadCommited'
        WHEN 3 THEN 'Repetable'
        WHEN 4 THEN 'Serializable'
        WHEN 5 THEN 'Snapshot'
        END as [transaction_isolation_level_desc]
      ,ER.[status]
      ,ES.[status] as [status_session]
      ,ER.[command]
      ,ER.[percent_complete]
      ,DB_Name(coalesce(ER.[database_id], ES.[database_id])) as [DBName]
      , SUBSTRING(
                    (select top(1) [text] from sys.dm_exec_sql_text(ER.[sql_handle]))
                  , ER.[statement_start_offset]/2+1
                  , (
                        CASE WHEN ((ER.[statement_start_offset]<0) OR (ER.[statement_end_offset]<0))
                                THEN DATALENGTH ((select top(1) [text] from sys.dm_exec_sql_text(ER.[sql_handle])))
                             ELSE ER.[statement_end_offset]
                        END
                        - ER.[statement_start_offset]
                    )/2 +1
                 ) as [CURRENT_REQUEST]
      ,(select top(1) [text] from sys.dm_exec_sql_text(ER.[sql_handle])) as [TSQL]
      ,(select top(1) [objectid] from sys.dm_exec_sql_text(ER.[sql_handle])) as [objectid]
      ,(select top(1) [query_plan] from sys.dm_exec_query_plan(ER.[plan_handle])) as [QueryPlan]
      ,NULL as [event_info]--(select top(1) [event_info] from sys.dm_exec_input_buffer(ES.[session_id], ER.[request_id])) as [event_info]
      ,ER.[wait_type]
      ,ES.[login_time]
      ,ES.[host_name]
      ,ES.[program_name]
      ,cast(ER.[wait_time]/1000 as decimal(18,3)) as [wait_timeSec]
      ,ER.[wait_time]
      ,ER.[last_wait_type]
      ,ER.[wait_resource]
      ,ER.[open_transaction_count]
      ,ER.[open_resultset_count]
      ,ER.[transaction_id]
      ,ER.[context_info]
      ,ER.[estimated_completion_time]
      ,ER.[cpu_time]
      ,ER.[total_elapsed_time]
      ,ER.[scheduler_id]
      ,ER.[task_address]
      ,ER.[reads]
      ,ER.[writes]
      ,ER.[logical_reads]
      ,ER.[text_size]
      ,ER.[language]
      ,ER.[date_format]
      ,ER.[date_first]
      ,ER.[quoted_identifier]
      ,ER.[arithabort]
      ,ER.[ansi_null_dflt_on]
      ,ER.[ansi_defaults]
      ,ER.[ansi_warnings]
      ,ER.[ansi_padding]
      ,ER.[ansi_nulls]
      ,ER.[concat_null_yields_null]
      ,ER.[transaction_isolation_level]
      ,ER.[lock_timeout]
      ,ER.[deadlock_priority]
      ,ER.[row_count]
      ,ER.[prev_error]
      ,ER.[nest_level]
      ,ER.[granted_query_memory]
      ,ER.[executing_managed_code]
      ,ER.[group_id]
      ,ER.[query_hash]
      ,ER.[query_plan_hash]
      ,EC.[most_recent_session_id]
      ,EC.[connect_time]
      ,EC.[net_transport]
      ,EC.[protocol_type]
      ,EC.[protocol_version]
      ,EC.[endpoint_id]
      ,EC.[encrypt_option]
      ,EC.[auth_scheme]
      ,EC.[node_affinity]
      ,EC.[num_reads]
      ,EC.[num_writes]
      ,EC.[last_read]
      ,EC.[last_write]
      ,EC.[net_packet_size]
      ,EC.[client_net_address]
      ,EC.[client_tcp_port]
      ,EC.[local_net_address]
      ,EC.[local_tcp_port]
      ,EC.[parent_connection_id]
      ,EC.[most_recent_sql_handle]
      ,ES.[host_process_id]
      ,ES.[client_version]
      ,ES.[client_interface_name]
      ,ES.[security_id]
      ,ES.[login_name]
      ,ES.[nt_domain]
      ,ES.[nt_user_name]
      ,ES.[memory_usage]
      ,ES.[total_scheduled_time]
      ,ES.[last_request_start_time]
      ,ES.[last_request_end_time]
      ,ES.[is_user_process]
      ,ES.[original_security_id]
      ,ES.[original_login_name]
      ,ES.[last_successful_logon]
      ,ES.[last_unsuccessful_logon]
      ,ES.[unsuccessful_logons]
      ,ES.[authenticating_database_id]
      ,ER.[sql_handle]
      ,ER.[statement_start_offset]
      ,ER.[statement_end_offset]
      ,ER.[plan_handle]
      ,NULL as [dop]--ER.[dop]
      ,coalesce(ER.[database_id], ES.[database_id]) as [database_id]
      ,ER.[user_id]
      ,ER.[connection_id]
from sys.dm_exec_requests ER with(readuncommitted)
right join sys.dm_exec_sessions ES with(readuncommitted)
on ES.session_id = ER.session_id 
left join sys.dm_exec_connections EC  with(readuncommitted)
on EC.session_id = ES.session_id
where ER.[status] in ('suspended', 'running', 'runnable')
or exists (select top(1) 1 from sys.dm_exec_requests as ER0 where ER0.[blocking_session_id]=ES.[session_id])

Questa richiesta visualizza tutte le richieste attive e tutte quelle richieste che bloccano esplicitamente le richieste attive.

Tutti questi e altri utili script sono implementati come rappresentazioni nel database SRV , che è distribuito liberamente. Ad esempio, il primo script proveniva dalla vista [inf]. [VBigQuery] e il secondo proveniva dalla vista [inf]. [VRequests] .

Esistono anche varie soluzioni di terze parti per la cronologia delle query. Uso Query Manager da Dbeaver : inserisci qui la descrizione dell'immagine e Query Execution History da SQL Tools , che è incorporato in SSMS : inserisci qui la descrizione dell'immagine


1

Questa funzione non esiste immediatamente in SSMS.

Se si utilizza SSMS 18 o versioni successive, è possibile provare SSMSPlus.

Ha una funzione di cronologia delle query.

https://github.com/akarzazi/SSMSPlus

Disclaimer: sono l'autore.


0

è possibile utilizzare "Genera script automaticamente su ogni salvataggio", se si utilizza Management Studio. Questo non è certamente il logging. Controlla se utile per te ..;)


0

Se le query a cui sei interessato sono query dinamiche che non riescono in modo intermittente, è possibile registrare l'SQL, il datetime e l'utente in una tabella al momento della creazione dell'istruzione dinamica. Sarebbe fatto caso per caso, anche se richiede una programmazione specifica e richiede un po 'di tempo di elaborazione in più, quindi fallo solo per quelle poche domande che ti preoccupano di più. Ma avere un registro delle istruzioni specifiche eseguite può davvero aiutare quando stai cercando di scoprire perché fallisce solo una volta al mese. Le query dinamiche sono difficili da testare a fondo e talvolta si ottiene un valore di input specifico che semplicemente non funzionerà e fare questa registrazione al momento della creazione di SQL è spesso il modo migliore per vedere cosa era specificamente nello sql che è stato creato.


0

Un metodo leggermente out-of-the-box sarebbe lo scripting di una soluzione in AutoHotKey. Lo uso, e non è perfetto, ma funziona ed è gratuito. In sostanza, questo script assegna un tasto di scelta rapida a CTRL+ SHIFT+ Rche copia l'SQL selezionato in SSMS ( CTRL+ C), salva un file SQL di datastamp e quindi esegue la query evidenziata ( F5). Se non sei abituato agli script AHK, il punto e virgola iniziale è un commento.

;CTRL+SHIFT+R to run a query that is first saved off
^+r::
;Copy
Send, ^c
; Set variables
EnvGet, HomeDir, USERPROFILE
FormatTime, DateString,,yyyyMMdd
FormatTime, TimeString,,hhmmss
; Make a spot to save the clipboard
FileCreateDir %HomeDir%\Documents\sqlhist\%DateString%
FileAppend, %Clipboard%, %HomeDir%\Documents\sqlhist\%DateString%\%TimeString%.sql
; execute the query
Send, {f5}
Return

Le maggiori limitazioni sono che questo script non funzionerà se si fa clic su "Esegui" anziché utilizzare la scorciatoia da tastiera, e questo script non salverà l'intero file, ma solo il testo selezionato. Tuttavia, è sempre possibile modificare lo script per eseguire la query, quindi selezionare tutto ( CTRL+ A) prima della copia / salvataggio.

L'uso di un editor moderno con le funzionalità "trova nei file" ti consentirà di effettuare ricerche nella cronologia di SQL. Potresti anche essere fantasioso e raschiare i tuoi file in un database SQLite3 per eseguire query sulle tue 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.