Query più “costose”
SELECT TOP 20 qs.sql_handle, qs.execution_count, qs.total_worker_time AS Total_CPU, total_CPU_inSeconds = --Converted from microseconds qs.total_worker_time/1000000, average_CPU_inSeconds = --Converted from microseconds (qs.total_worker_time/1000000) / qs.execution_count, qs.total_elapsed_time, total_elapsed_time_inSeconds = --Converted from microseconds qs.total_elapsed_time/1000000, st.text, qp.query_plan FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st CROSS apply sys.dm_exec_query_plan (qs.plan_handle) AS qp ORDER BY qs.total_worker_time DESC;
Strutture indici
SELECT Tab.name Table_Name ,IX.name Index_Name ,IX.type_desc Index_Type ,Col.name Index_Column_Name ,IXC.is_included_column Is_Included_Column ,IX.fill_factor ,IX.is_disabled ,IX.is_primary_key ,IX.is_unique FROM sys.indexes IX INNER JOIN sys.index_columns IXC ON IX.object_id = IXC.object_id AND IX.index_id = IXC.index_id INNER JOIN sys.columns Col ON IX.object_id = Col.object_id AND IXC.column_id = Col.column_id INNER JOIN sys.tables Tab ON IX.object_id = Tab.object_id;
Informazioni sulle tabelle
SELECT FullName = s.name + '.' + t.name ,SchemaName = s.name ,TableName = t.name FROM sys.tables t JOIN sys.schemas s ON s.schema_id = t.schema_id ORDER BY s.name, t.name; SELECT * FROM (SELECT TableName = t.TABLE_SCHEMA + '.' + t.TABLE_NAME ,[RowCount] = SUM(sp.[rows]) ,Megabytes = (8 * SUM(CASE WHEN sau.type != 1 THEN sau.used_pages WHEN sp.index_id < 2 THEN sau.data_pages ELSE 0 END)) / 1024 FROM INFORMATION_SCHEMA.TABLES t JOIN sys.partitions sp ON sp.object_id = OBJECT_ID(t.TABLE_SCHEMA + '.' + t.TABLE_NAME) JOIN sys.allocation_units sau ON sau.container_id = sp.partition_id WHERE TABLE_TYPE = 'BASE TABLE' GROUP BY t.TABLE_SCHEMA + '.' + t.TABLE_NAME ) A ORDER BY TableName;
Mostra constraints
select table_view, object_type, constraint_type, constraint_name, details from (select schema_name(t.schema_id) + '.' + t.[name] as table_view, case when t.[type] = 'U' then 'Table' when t.[type] = 'V' then 'View' end as [object_type], case when c.[type] = 'PK' then 'Primary key' when c.[type] = 'UQ' then 'Unique constraint' when i.[type] = 1 then 'Unique clustered index' when i.type = 2 then 'Unique index' end as constraint_type, isnull(c.[name], i.[name]) as constraint_name, substring(column_names, 1, len(column_names)-1) as [details] from sys.objects t left outer join sys.indexes i on t.object_id = i.object_id left outer join sys.key_constraints c on i.object_id = c.parent_object_id and i.index_id = c.unique_index_id cross apply (select col.[name] + ', ' from sys.index_columns ic inner join sys.columns col on ic.object_id = col.object_id and ic.column_id = col.column_id where ic.object_id = t.object_id and ic.index_id = i.index_id order by col.column_id for xml path ('') ) D (column_names) where is_unique = 1 and t.is_ms_shipped <> 1 union all select schema_name(fk_tab.schema_id) + '.' + fk_tab.name as foreign_table, 'Table', 'Foreign key', fk.name as fk_constraint_name, schema_name(pk_tab.schema_id) + '.' + pk_tab.name from sys.foreign_keys fk inner join sys.tables fk_tab on fk_tab.object_id = fk.parent_object_id inner join sys.tables pk_tab on pk_tab.object_id = fk.referenced_object_id inner join sys.foreign_key_columns fk_cols on fk_cols.constraint_object_id = fk.object_id union all select schema_name(t.schema_id) + '.' + t.[name], 'Table', 'Check constraint', con.[name] as constraint_name, con.[definition] from sys.check_constraints con left outer join sys.objects t on con.parent_object_id = t.object_id left outer join sys.all_columns col on con.parent_column_id = col.column_id and con.parent_object_id = col.object_id union all select schema_name(t.schema_id) + '.' + t.[name], 'Table', 'Default constraint', con.[name], col.[name] + ' = ' + con.[definition] from sys.default_constraints con left outer join sys.objects t on con.parent_object_id = t.object_id left outer join sys.all_columns col on con.parent_column_id = col.column_id and con.parent_object_id = col.object_id) a order by table_view, constraint_type, constraint_name;
Se SQL Server funziona lentamente, uno dei primi passi e' capire cosa sta funzionando in questo momento. Uno dei modi migliori per farlo è con sp_whoisactive. Questo differisce da sys.sysprocesses perché solo mostra i processi che eseguono una query in questo momento, non gli SPID inattivi.
Si puo' scaricare sp_whoisactive direttamente da GitHub https://github.com/amachanic/sp_whoisactive/releases.
EXEC sp_whoisactive;
La prima colonna è la durata della query, quindi puoi evitare di guardare le query che hanno funzionato solo per una frazione di secondo.
A volte ricevi un avviso di prestazioni lente, ma si cancella prima che tu possa eseguire sp_whoisactive. Fortunatamente, possiamo ottenere la cache del piano delle query più costose.
WITH qs AS ( SELECT TOP 10 total_worker_time/execution_count AvgCPU , total_elapsed_time/execution_count AvgDuration , (total_logical_reads + total_physical_reads)/execution_count AvgReads , execution_count , sql_handle , plan_handle , statement_start_offset , statement_end_offset FROM sys.dm_exec_query_stats WHERE execution_count > 5 AND min_logical_reads > 100 AND min_worker_time > 100 ORDER BY (total_logical_reads + total_physical_reads)/execution_count DESC) SELECT AvgCPU , AvgDuration , AvgReads , execution_count ,SUBSTRING(st.TEXT, (qs.statement_start_offset/2) + 1, ((CASE qs.statement_end_offset WHEN -1 THEN DATALENGTH(st.TEXT) ELSE qs.statement_end_offset END - qs.statement_start_offset)/2) + 1) StatementText ,query_plan ExecutionPlan FROM qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS st CROSS APPLY sys.dm_exec_query_plan (qs.plan_handle) AS qp ORDER BY AvgDuration DESC;
A volte il problema è il lock. Nel dubbio, si possono usare queste due query:
SELECT * FROM sys.sysprocesses WHERE blocked > 0 OR SPID IN (SELECT Blocked FROM sys.sysprocesses);
La colonna “bloccato” mostra 0 quando un SPID non viene bloccato e mostra il blocco SPID quando viene bloccato. Questa query mostra tutto processi bloccati o che stanno bloccando qualcuno.
A volte si verifica un problema di blocco quando qualcuno apre una transazione esplicita e dimentica di chiuderlo. L'esecuzione di questo comando ti dirà l'apertura più vecchia transazione. È ragionevole che questo restituisca un valore dall'ultimo pochi secondi, ma se mostra una data / ora da diversi minuti o ore fa, quello indica un problema
DBCC OPENTRAN();
SQL Server tiene traccia delle attese sperimentate da ogni processo in esecuzione sul server. Ogni tipo di attesa inizia a 0 ms ogni volta che il servizio viene avviato e conta da Là. Per avere un'idea di ciò che sta accadendo in questo momento, devi confrontare i numeri da un punto nel tempo a un altro. Questo script farà proprio questo confrontando il DMV con un'istantanea di se stesso da 15 secondi prima.
SELECT wait_type , waiting_tasks_count , signal_wait_time_ms , wait_time_ms , SysDateTime() AS StartTime INTO #WaitStatsBefore FROM sys.dm_os_wait_stats WHERE wait_type NOT IN ('SLEEP_TASK','BROKER_EVENTHANDLER','XE_DISPATCHER_WAIT','BROKER_RECEIVE_WAITFOR', 'CLR_AUTO_EVENT', 'CLR_MANUAL_EVENT','REQUEST_FOR_DEADLOCK_SEARCH','SQLTRACE_INCREMENTAL_FLUSH_SLEEP','SQLTRACE_BUFFER_FLUSH','LAZYWRITER_SLEEP','XE_TIMER_EVENT','XE_DISPATCHER_WAIT','FT_IFTS_SCHEDULER_IDLE_WAIT','LOGMGR_QUEUE','CHECKPOINT_QUEUE', 'BROKER_TO_FLUSH', 'BROKER_TASK_STOP', 'BROKER_EVENTHANDLER', 'SLEEP_TASK', 'WAITFOR', 'DBMIRROR_DBM_MUTEX', 'DBMIRROR_EVENTS_QUEUE', 'DBMIRRORING_CMD', 'DISPATCHER_QUEUE_SEMAPHORE','BROKER_RECEIVE_WAITFOR', 'CLR_AUTO_EVENT', 'DIRTY_PAGE_POLL', 'HADR_FILESTREAM_IOMGR_IOCOMPLETION', 'ONDEMAND_TASK_QUEUE', 'FT_IFTSHC_MUTEX', 'CLR_MANUAL_EVENT', 'SP_SERVER_DIAGNOSTICS_SLEEP', 'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP', 'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP','CLR_SEMAPHORE','DBMIRROR_WORKER_QUEUE','SP_SERVER_DIAGNOSTICS_SLEEP','HADR_CLUSAPI_CALL','HADR_LOGCAPTURE_WAIT','HADR_NOTIFICATION_DEQUEUE','HADR_TIMER_TASK','HADR_WORK_QUEUE','REDO_THREAD_PENDING_WORK','UCS_SESSION_REGISTRATION','BROKER_TRANSMITTER','SLEEP_SYSTEMTASK','QDS_SHUTDOWN_QUEUE');--These are a series of irrelevant wait stats. WAITFOR DELAY '00:00:15'; --15 seconds SELECT a.wait_type , a.signal_wait_time_ms - b.signal_wait_time_ms AS CPUDiff , (a.wait_time_ms - b.wait_time_ms) - (a.signal_wait_time_ms - b.signal_wait_time_ms) AS ResourceDiff , a.waiting_tasks_count - b.waiting_tasks_count AS waiting_tasks_diff , CAST(CAST(a.wait_time_ms - b.wait_time_ms AS FLOAT) / (a.waiting_tasks_count - b.waiting_tasks_count) AS DECIMAL(10,1)) AS AverageDurationMS , a.max_wait_time_ms max_wait_all_timeMS , DATEDIFF(ms,StartTime, SysDateTime()) AS DurationSeconds FROM sys.dm_os_wait_stats a INNER JOIN #WaitStatsBefore b ON a.wait_type = b.wait_type WHERE a.signal_wait_time_ms <> b.signal_wait_time_ms OR a.wait_time_ms <> b.wait_time_ms ORDER BY 3 DESC;
SQL Server tiene traccia dei ritardi riscontrati durante l'interazione con i dati e il registro File. Come le statistiche di attesa, questi contatori iniziano da 0 ogni volta che il servizio è iniziato. Il prossimo script creerà una tabella temporanea per memorizzare un'istantanea di i numeri, attendi 15 secondi, quindi vedi cosa è cambiato.
SELECT b.name , a.database_id , a.[FILE_ID] , a.num_of_reads , a.num_of_bytes_read , a.io_stall_read_ms , a.num_of_writes , a.num_of_bytes_written , a.io_stall_write_ms , a.io_stall , GetDate() AS StartTime INTO #IOStatsBefore FROM sys.dm_io_virtual_file_stats(NULL, NULL) a INNER JOIN sys.databases b ON a.database_id = b.database_id; WAITFOR DELAY '00:00:15' SELECT a.name DatabaseName , a.[FILE_ID] , (b.io_stall_read_ms - a.io_stall_read_ms)/ CAST(1000 as DECIMAL(10,1)) io_stall_read_Diff , (b.io_stall_write_ms - a.io_stall_write_ms)/ CAST(1000 as DECIMAL(10,1)) io_stall_write_Diff , (b.io_stall - a.io_stall)/ CAST(1000 as DECIMAL(10,1)) io_stall_Diff , DATEDIFF(s,StartTime, GETDATE()) AS DurationSeconds FROM #IOStatsBefore a INNER JOIN sys.dm_io_virtual_file_stats(NULL, NULL) b ON a.database_id = b.database_id AND a.[file_id] = b.[file_id] ORDER BY a.name , a.[FILE_ID];
SQL Server tiene traccia nativamente della cronologia di utilizzo della CPU di un'istanza una volta per minuto per gli ultimi 250 minuti. Puoi ottenere quelle letture usando la seguente query. Se le prestazioni sono disattivate, confrontare gli ultimi 30 minuti con i 220 precedenti per vedere se l'utilizzo della CPU è aumentato mentre gli utenti si sono lamentati delle prestazioni problemi.
WITH XMLRecords AS ( SELECT DATEADD (ms, r.[timestamp] - sys.ms_ticks,SYSDATETIME()) AS record_time , CAST(r.record AS XML) record FROM sys.dm_os_ring_buffers r CROSS JOIN sys.dm_os_sys_info sys WHERE ring_buffer_type='RING_BUFFER_SCHEDULER_MONITOR' AND record LIKE '%<SystemHealth>%') SELECT 100-record.value('(./Record/SchedulerMonitorEvent/SystemHealth/SystemIdle)[1]', 'int') AS SystemUtilization , record.value('(./Record/SchedulerMonitorEvent/SystemHealth/ProcessUtilization)[1]', 'int') AS SQLProcessUtilization , record_time FROM XMLRecords;
A volte un disco completo può causare un problema di prestazioni. Utilizzare questa query per analizzare rapidamente tutti i volumi logici contenenti almeno un dato o registro di SQL Server File.
SELECT DISTINCT vs.volume_mount_point Drive , vs.logical_volume_name , vs.total_bytes/1024/1024/1024 CapacityGB , vs.available_bytes/1024/1024/1024 FreeGB , CAST(vs.available_bytes * 100. / vs.total_bytes AS DECIMAL(4,1)) FreePct FROM sys.master_files mf CROSS APPLY sys.dm_os_volume_stats(mf.database_id, mf.file_id) AS vs;