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?
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?
Risposte:
[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;
sys.dm_exec_query_statse cercare o ordinare dalast_execution_time
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
Il pacchetto di strumenti SSMS aggiunge funzionalità per registrare la cronologia di esecuzione, tra le altre cose.
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.
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())
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
È possibile monitorare le query SQL da SQL Profiler se necessario
La cronologia delle query può essere visualizzata utilizzando le viste di sistema:
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 :
e Query Execution History da SQL Tools , che è incorporato in SSMS :

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.
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.
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.