什么?有个 SQL 执行了 8 秒!
哪里出了问题?臣妾不知道啊,得找 DBA 啊。
DBA 人呢?离职了!!擦!!!
程序员在无处寻求帮助时,就得想办法自救,努力让自己变成 "伪 DBA"。
索引
- 按页编号查看数据表信息
- 获取查询 SELECT 语句的执行次数排名
- 看看哪些 Ad-hoc Query 在浪费资源
- 查看当前处于等待状态的 Task 在等什么
- 查询谁在占着 Session 连接
- 查询程序占用的 SPID 信息
- 查询所有执行 SQL 对应的 sql_handle
- 查询最近 60 秒平均执行时间超过 300 毫秒的 SQL 语句
- 查询最近 60 秒平均执行时间超过 100 毫秒的非 SELECT 语句
- 查询最近 60 秒累计总执行次数大于 1000 次的 SQL 语句
- 查询前 10 个可能是性能最差的 SQL 语句
- 看看当前哪些查询正在活跃着
按页编号查看数据表信息
SELECT sc. [ name ] AS [ schema ] ,o. [ name ] AS [ table_name ] ,o.type_desc ,obd. [ file_id ] ,obd.page_id ,obd.page_level ,obd.row_count ,obd.free_space_in_bytes ,obd.is_modified ,obd.numa_node FROM sys.dm_os_buffer_descriptors AS obd JOIN sys.allocation_units AS au ON obd.allocation_unit_id = au.allocation_unit_id JOIN sys.partitions AS p ON au.container_id = p.partition_id JOIN sys.objects AS o ON p. [ object_id ] = o. [ object_id ] JOIN sys.schemas AS sc ON o. [ schema_id ] = sc. [ schema_id ] WHERE database_id = DB_ID () AND o.is_ms_shipped = 0 ORDER BY obd.page_id ,o. [ name ]
获取查询 SELECT 语句的执行次数排名
SQL Server 2012 版本
SELECT TOP ( 100 ) qs.execution_count ,qs.total_rows ,qs.last_rows ,qs.min_rows ,qs.max_rows ,qs.last_elapsed_time ,qs.min_elapsed_time ,qs.max_elapsed_time ,total_worker_time ,total_logical_reads , SUBSTRING (qt. [ text ] , qs.statement_start_offset / 2 + 1 , ( CASE WHEN qs.statement_end_offset = - 1 THEN LEN ( CONVERT ( NVARCHAR ( MAX ), qt. [ text ] )) * 2 ELSE qs.statement_end_offset END - qs.statement_start_offset ) / 2 ) AS query_text FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt ORDER BY qs.execution_count DESC OPTION (RECOMPILE);
SQL Server 2008 R2 版本
SELECT TOP ( 100 ) qs.execution_count ,qs.last_elapsed_time ,qs.min_elapsed_time ,qs.max_elapsed_time ,total_worker_time ,total_logical_reads , SUBSTRING (qt. [ text ] , qs.statement_start_offset / 2 + 1 , ( CASE WHEN qs.statement_end_offset = - 1 THEN LEN ( CONVERT ( NVARCHAR ( MAX ), qt. [ text ] )) * 2 ELSE qs.statement_end_offset END - qs.statement_start_offset ) / 2 ) AS query_text FROM sys.dm_exec_query_stats AS qs WITH (NOLOCK) CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) AS qt ORDER BY qs.execution_count DESC OPTION (RECOMPILE);
看看哪些 Ad-hoc Query 在浪费资源
SELECT TOP ( 50 ) [ text ] AS [ QueryText ] ,cp.cacheobjtype ,cp.objtype ,cp.size_in_bytes / 1024 AS [ Plan Size in KB ] FROM sys.dm_exec_cached_plans AS cp WITH (NOLOCK) CROSS APPLY sys.dm_exec_sql_text(plan_handle) WHERE cp.cacheobjtype = N ' Compiled Plan ' AND cp.objtype IN ( N ' Adhoc ' ,N ' Prepared ' ) AND cp.usecounts = 1 ORDER BY cp.size_in_bytes DESC OPTION (RECOMPILE);
查看当前处于等待状态的 Task 在等什么
SELECT dm_ws.wait_duration_ms ,dm_ws.wait_type ,dm_es.STATUS ,dm_t. TEXT ,dm_qp.query_plan ,dm_ws.session_ID ,dm_es.cpu_time ,dm_es.memory_usage ,dm_es.logical_reads ,dm_es.total_elapsed_time ,dm_es.program_name , DB_NAME (dm_r.database_id) DatabaseName ,dm_ws.blocking_session_id ,dm_r.wait_resource ,dm_es.login_name ,dm_r.command ,dm_r.last_wait_type FROM sys.dm_os_waiting_tasks dm_ws INNER JOIN sys.dm_exec_requests dm_r ON dm_ws.session_id = dm_r.session_id INNER JOIN sys.dm_exec_sessions dm_es ON dm_es.session_id = dm_r.session_id CROSS APPLY sys.dm_exec_sql_text(dm_r.sql_handle) dm_t CROSS APPLY sys.dm_exec_query_plan(dm_r.plan_handle) dm_qp WHERE dm_es.is_user_process = 1 ;
查询谁在占着 Session 连接
CREATE TABLE #sp_who2 ( SPID INT ,STATUS VARCHAR ( 255 ) ,LOGIN VARCHAR ( 255 ) ,HostName VARCHAR ( 255 ) ,BlkBy VARCHAR ( 255 ) ,DBName VARCHAR ( 255 ) ,Command VARCHAR ( 255 ) ,CPUTime INT ,DiskIO INT ,LastBatch VARCHAR ( 255 ) ,ProgramName VARCHAR ( 255 ) ,SPID2 INT ,REQUESTID INT ) INSERT INTO #sp_who2 EXEC sp_who2 SELECT * FROM #sp_who2 w -- WHERE w.ProgramName = 'xxx' DROP TABLE #sp_who2
查询程序占用的 SPID 信息
SELECT spid ,a. [ status ] ,hostname ,program_name ,cmd ,cpu ,physical_io ,blocked ,b. [ name ] ,loginame FROM master.dbo.sysprocesses a INNER JOIN master.dbo.sysdatabases b ON a.dbid = b.dbid where hostname != '' ORDER BY program_name
查询所有执行 SQL 对应的 sql_handle
DECLARE @current_sql_handle BINARY ( 20 ); DECLARE @sql_text_list TABLE ( sql_handle BINARY ( 20 ) , TEXT NVARCHAR ( max ) ); DECLARE sql_handle_cursor CURSOR FOR SELECT sp.sql_handle FROM sys.sysprocesses sp WHERE sp.sql_handle != 0x0000000000000000000000000000000000000000 -- AND sp.program_name = 'xxxx' ; OPEN sql_handle_cursor FETCH NEXT FROM sql_handle_cursor INTO @current_sql_handle WHILE @@FETCH_STATUS = 0 BEGIN INSERT INTO @sql_text_list ( sql_handle , TEXT ) SELECT @current_sql_handle ,est. TEXT FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text( @current_sql_handle ) est; FETCH NEXT FROM sql_handle_cursor INTO @current_sql_handle END SELECT DISTINCT * FROM @sql_text_list tl WHERE tl. TEXT NOT LIKE ' %statement_start_offset% ' ; CLOSE sql_handle_cursor DEALLOCATE sql_handle_cursor
查询最近 60 秒平均执行时间超过 300 毫秒的 SQL 语句
SELECT SUBSTRING (st. TEXT , (qs.statement_start_offset / 2 ) + 1 , ( ( ( CASE statement_end_offset WHEN - 1 THEN DATALENGTH (st. TEXT ) ELSE qs.statement_end_offset END ) - qs.statement_start_offset ) / 2 ) + 1 ) AS statement_text ,last_execution_time ,total_elapsed_time / execution_count avg_elapsed_time ,total_physical_reads ,total_logical_reads ,total_logical_writes ,execution_count ,total_worker_time ,total_elapsed_time ,creation_time FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st WHERE last_execution_time > DATEADD (SECOND, - 60 , GETDATE ()) AND st. TEXT NOT LIKE ' %statement_start_offset% ' AND total_elapsed_time / execution_count >= 300 ORDER BY last_execution_time DESC ;
查询最近 60 秒平均执行时间超过 100 毫秒的非 SELECT 语句
SELECT SUBSTRING (st. TEXT , (qs.statement_start_offset / 2 ) + 1 , ( ( ( CASE statement_end_offset WHEN - 1 THEN DATALENGTH (st. TEXT ) ELSE qs.statement_end_offset END ) - qs.statement_start_offset ) / 2 ) + 1 ) AS statement_text ,last_execution_time ,total_elapsed_time / execution_count avg_elapsed_time ,total_physical_reads ,total_logical_reads ,total_logical_writes ,execution_count ,total_worker_time ,total_elapsed_time ,creation_time FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st WHERE last_execution_time > DATEADD (SECOND, - 60 , GETDATE ()) AND st. TEXT NOT LIKE ' %statement_start_offset% ' AND execution_count < 100 AND total_elapsed_time / execution_count > 100 AND SUBSTRING (st. TEXT , (qs.statement_start_offset / 2 ) + 1 , ( ( ( CASE statement_end_offset WHEN - 1 THEN DATALENGTH (st. TEXT ) ELSE qs.statement_end_offset END ) - qs.statement_start_offset ) / 2 ) + 1 ) NOT LIKE ' SELECT% ' ORDER BY last_execution_time DESC ;
查询最近 60 秒累计总执行次数大于 1000 次的 SQL 语句
SELECT SUBSTRING (st. TEXT , (qs.statement_start_offset / 2 ) + 1 , ( ( ( CASE statement_end_offset WHEN - 1 THEN DATALENGTH (st. TEXT ) ELSE qs.statement_end_offset END ) - qs.statement_start_offset ) / 2 ) + 1 ) AS statement_text ,total_elapsed_time / execution_count / 1000 AS avg_elapsed_time_by_ms ,last_execution_time ,total_elapsed_time ,execution_count ,total_worker_time ,total_physical_reads ,total_logical_reads ,total_logical_writes ,creation_time FROM sys.dm_exec_query_stats AS qs CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st WHERE qs.execution_count > 1000 AND last_execution_time > DATEADD (SECOND, - 60 , GETDATE ()) -- AND ( -- st.TEXT LIKE '%[[]AAA]%' -- OR st.TEXT LIKE '%[[]BBB]%' -- OR st.TEXT LIKE '%[[]CCC]%' -- ) ORDER BY total_elapsed_time / execution_count DESC ;
查询前 10 个可能是性能最差的 SQL 语句
SELECT TOP 10 TEXT AS ' SQL Statement ' ,last_execution_time AS ' Last Execution Time ' ,(total_logical_reads + total_physical_reads + total_logical_writes) / execution_count AS [ Average IO ] ,(total_worker_time / execution_count) / 1000000.0 AS [ Average CPU Time (sec) ] ,(total_elapsed_time / execution_count) / 1000000.0 AS [ Average Elapsed Time (sec) ] ,execution_count AS "Execution Count " ,qp.query_plan AS "Query Plan " FROM sys.dm_exec_query_stats qs CROSS APPLY sys.dm_exec_sql_text(qs.plan_handle) st CROSS APPLY sys.dm_exec_query_plan(qs.plan_handle) qp ORDER BY total_elapsed_time / execution_count DESC
看看当前哪些查询正在活跃着
Adam Machanic 发布了一个查询活跃 SQL 的查询脚本,篇幅极长,请到发布地址下载。
《人人都是 DBA》系列文章索引:
本系列文章《 人人都是 DBA 》由 Dennis Gao 发表自 博客园 ,未经作者本人同意禁止任何形式的转载,任何自动或人为的爬虫转载行为均为耍流氓。