首页 > 数据库 >找出SQLServer数据库I/O高的原因

找出SQLServer数据库I/O高的原因

时间:2023-04-27 22:12:45浏览次数:57  
标签:qs writes 数据库 SQLServer 找出 id reads num sum

找出SQLServer数据库I/O高的原因

影响SQLServer性能的因素有很多,比如CPU、I/O、内存、错误的执行计划、不恰当的索引或缺少索引等。

当查询变慢时,我发现最常见的一件事是由于查询执行的I/O太大。当一个查询因为I/O而变慢时,可能是因为糟糕的硬件、糟糕的执行计划,但通常是糟糕的数据库设计或缺乏适当的索引。

当你想测量或改进I/O,或者寻找那些使用大量I/O的查询时,你会去哪里?在本文中,我将探索测量和识别数据库实例的I/O相关性能信息的方法。

 

哪些数据库的执行了I/O

首先是要找出哪些数据库指定的I/O;量比较大。知道数据库的I/O性能有助于知道该具体关注哪些数据库。

有很多方法来查看,这里只是介绍使用Dynamic Management Function(DMF)和Dynamic Management Views(DMVs) 。他们是在SQLServer 2005中引入,在2008中得到加强。

DMVs和DMFs收集自sqlserver启动后直至关闭期间的统计信息。收集的信息不会被持久化。可以从sys.dm_io_virtual_file_stats来分析数据库的I/O。

select
	name as 'database name',
	sum ( num_of_reads ) as '读的次数',
	sum ( num_of_bytes_read/1024/1024/1024 ) as 'read(GB)', 
	sum ( num_of_writes ) as '写的次数', 
	sum ( num_of_bytes_written/1024/1024/1024 ) as 'writes(GB)' 
from
	sys.dm_io_virtual_file_stats ( null, null ) i
	inner join sys.databases d on i.database_id = d.database_id 
group by
	name
order by 3 desc, 5 desc;

结果展示:这是自启动后的I/O统计,不能显示当前状态的I/O

 

查看每个数据库最近5分钟的I/O

(执行会有点耗时)

declare @sample table (
  dbname varchar(128) 
 ,numberofreads bigint
 ,numberofwrites bigint
 ,sizeofreads int
 ,sizeofwrites int
 )

insert into @sample 
select name as 'dbname'
      ,sum(num_of_reads) as 'numberofread'
      ,sum(num_of_writes) as 'numberofwrites' 
      ,sum(num_of_bytes_read/1024/1024/1024) as 'sizeofreads'
      ,sum(num_of_bytes_written/1024/1024/1024) as 'sizeofwrites' 
from sys.dm_io_virtual_file_stats(null, null) i
  inner join sys.databases d  
      on i.database_id = d.database_id
group by name 

waitfor delay '00:05:00.000';

select firstsample.dbname
      ,(secondsample.numberofreads - firstsample.numberofreads) as 'number of reads'
      ,(secondsample.numberofwrites - firstsample.numberofwrites) as 'number of writes'
      ,(secondsample.sizeofreads - firstsample.sizeofreads) as 'reads(GB)'
      ,(secondsample.sizeofwrites - firstsample.sizeofwrites) as 'writes(GB)'
from 
(select * from @sample) firstsample
inner join
(select name as 'dbname'
      ,sum(num_of_reads) as 'numberofreads'
      ,sum(num_of_writes) as 'numberofwrites' 
      ,sum(num_of_bytes_read/1024/1024/1024) as 'sizeofreads'
      ,sum(num_of_bytes_written/1024/1024/1024) as 'sizeofwrites' 
from sys.dm_io_virtual_file_stats(null, null) i
  inner join sys.databases d  
      on i.database_id = d.database_id
group by name) as secondsample
on firstsample.dbname = secondsample.dbname
;

 

查看物理磁盘分区的I/O

select left(f.physical_name, 1) as driveletter, 
	dateadd(ms,sample_ms * -1, getdate()) as [start date],
	sum(v.num_of_writes) as total_num_of_writes, 
	sum(v.num_of_bytes_written) as total_num_of_bytes_written, 
	sum(v.num_of_reads) as total_num_of_reads, 
	sum(v.num_of_bytes_read) as total_num_of_bytes_read, 
	sum(v.size_on_disk_bytes) as total_size_on_disk_bytes
from sys.master_files f
inner join sys.dm_io_virtual_file_stats(null, null) v
on f.database_id=v.database_id and f.file_id=v.file_id
group by left(f.physical_name, 1),dateadd(ms,sample_ms * -1, getdate());

 

 

查看磁盘的延迟

使用io_stall*列来统计磁盘延迟

select  left(physical_name, 1) as drive,
        cast(sum(io_stall_read_ms) / 
            (1.0 + sum(num_of_reads)) as numeric(10,1)) 
                          as 'avg_read_disk_latency_ms',
        cast(sum(io_stall_write_ms) / 
            (1.0 + sum(num_of_writes) ) as numeric(10,1)) 
                          as 'avg_write_disk_latency_ms',
        cast((sum(io_stall)) / 
            (1.0 + sum(num_of_reads + num_of_writes)) as numeric(10,1)) 
                          as 'avg_disk_latency_ms'
from    sys.dm_io_virtual_file_stats(null, null) as divfs
        join sys.master_files as mf on mf.database_id = divfs.database_id
                                       and mf.file_id = divfs.file_id
group by left(physical_name, 1)
order by avg_disk_latency_ms desc;

 

查看文件的延迟

SELECT
    [ReadLatency] =
        CASE WHEN [num_of_reads] = 0
            THEN 0 ELSE ([io_stall_read_ms] / [num_of_reads]) END,
    [WriteLatency] =
        CASE WHEN [num_of_writes] = 0
            THEN 0 ELSE ([io_stall_write_ms] / [num_of_writes]) END,
    [Latency] =
        CASE WHEN ([num_of_reads] = 0 AND [num_of_writes] = 0)
            THEN 0 ELSE ([io_stall] / ([num_of_reads] + [num_of_writes])) END,
    [AvgBPerRead] =
        CASE WHEN [num_of_reads] = 0
            THEN 0 ELSE ([num_of_bytes_read] / [num_of_reads]) END,
    [AvgBPerWrite] =
        CASE WHEN [num_of_writes] = 0
            THEN 0 ELSE ([num_of_bytes_written] / [num_of_writes]) END,
    [AvgBPerTransfer] =
        CASE WHEN ([num_of_reads] = 0 AND [num_of_writes] = 0)
            THEN 0 ELSE
                (([num_of_bytes_read] + [num_of_bytes_written]) /
                ([num_of_reads] + [num_of_writes])) END,
    LEFT ([mf].[physical_name], 2) AS [Drive],
    DB_NAME ([vfs].[database_id]) AS [DB],
    [mf].[physical_name]
FROM
    sys.dm_io_virtual_file_stats (NULL,NULL) AS [vfs]
JOIN sys.master_files AS [mf]
    ON [vfs].[database_id] = [mf].[database_id]
    AND [vfs].[file_id] = [mf].[file_id]
-- WHERE [vfs].[file_id] = 2 -- log files
-- ORDER BY [Latency] DESC
-- ORDER BY [ReadLatency] DESC
ORDER BY [WriteLatency] DESC;
GO

建议延迟应该在30ms以下。

 

找出消耗I/O的top SQL

select top 25 DB_NAME( st.[dbid] ) AS [Database]
      ,cp.usecounts as [execution_count]
      ,qs.total_worker_time as cpu
      ,qs.total_elapsed_time as elapsed_time
      ,qs.total_logical_reads as logical_reads
      ,qs.total_logical_writes as logical_writes
      ,qs.total_physical_reads as physical_reads 
      ,qs.creation_time AS [CreationTime]
      ,substring(text, 
                   case when statement_start_offset = 0 
                          or statement_start_offset is null  
                           then 1  
                           else statement_start_offset/2 + 1 end, 
                   case when statement_end_offset = 0 
                          or statement_end_offset = -1  
                          or statement_end_offset is null  
                           then len(text)  
                           else statement_end_offset/2 end - 
                     case when statement_start_offset = 0 
                            or statement_start_offset is null 
                             then 1  
                             else statement_start_offset/2  end + 1 
                  )  as [statement]
      ,st.text AS [Complete Query Text]				  
from sys.dm_exec_query_stats qs  
   join sys.dm_exec_cached_plans cp on qs.plan_handle = cp.plan_handle 
   cross apply sys.dm_exec_sql_text(cp.plan_handle) st
order by qs.total_logical_reads desc;

SELECT TOP
        ( 25 ) DB_NAME( t.[dbid] ) AS [Database],
        REPLACE( REPLACE( LEFT ( t.[text], 255 ), CHAR ( 10 ), '' ), CHAR ( 13 ), '' ) AS [ShortQueryTXT],
        qs.total_logical_reads AS [TotalLogicalReads],
        qs.min_logical_reads AS [MinLogicalReads],
        qs.total_logical_reads/ qs.execution_count AS [AvgLogicalReads],
        qs.max_logical_reads AS [MaxLogicalReads],
    qs.total_physical_reads AS [TotalPhysicalReads],
    qs.min_physical_reads AS [MinPhysicalReads],
    qs.total_physical_reads/ qs.execution_count AS [AvgPhysicalReads],
    qs.max_physical_reads AS [MaxPhysicalReads],
        qs.min_worker_time AS [MinWorkerTime],
        qs.total_worker_time/ qs.execution_count AS [AvgWorkerTime],
        qs.max_worker_time AS [MaxWorkerTime],
        qs.min_elapsed_time AS [MinElapsedTime],
        qs.total_elapsed_time/ qs.execution_count AS [AvgElapsedTime],
        qs.max_elapsed_time AS [MaxElapsedTime],
        qs.execution_count AS [ExecutionCount],
CASE
                WHEN CONVERT ( nvarchar ( MAX ), qp.query_plan ) LIKE N'%%' THEN
                1 ELSE 0
        END AS [HasMissingIX],
        qs.creation_time AS [CreationTime],
        t.[text] AS [Complete Query Text],
        qp.query_plan AS [QueryPlan]
FROM
        sys.dm_exec_query_stats AS qs WITH ( NOLOCK ) 
		CROSS APPLY sys.dm_exec_sql_text ( plan_handle ) AS t CROSS APPLY sys.dm_exec_query_plan ( plan_handle ) AS qp
ORDER BY
        (total_logical_reads + total_logical_writes) / Execution_count DESC OPTION ( RECOMPILE )

sys.dm_exec_query_plan包含的执行计划可以是缓存的、也可以是正在执行的。

 

标签:qs,writes,数据库,SQLServer,找出,id,reads,num,sum
From: https://www.cnblogs.com/abclife/p/17333038.html

相关文章

  • Sqlserver修改表结构提示不允许保存更改。
    在现有的表中去修改或者增加表字段的时候就会提示:不允许保存更改。您所做的更改要求删除并创建一下表。您对无法重新创建的表进行了更改或启用了“阻止保存要求重新创建表的更改”选项。、如何解决问题:操作步骤:点击“工具”→“选项”→"打开弹窗中选择(设计器)" →"表设......
  • 数据库CSV文件打开乱码如何调整
    数据库文件打开乱码,我们该如何设置调整好,按步骤调整即可查看需要的数据第一步:新建excel表格文件第二步:导入excel数据文件 第三步:选择语言转换数据 第四步:添加文本执行 第五步:修改文本类型 第六步:关闭保存查看数据库文件表格显示正常 ......
  • 关于sap-hana-数据库-在pacemaker集群中迁移主控节点-master节点
    环境介绍,hana数据库的两个节点:azphxxxdb01azphxxxdb02目前master位于azphxxxdb02,现在需要切换回azphxxxdb01 需要确保Pacemaker没有任何失败的操作(通过pcs状态检查)、没有任何意外的位置约束(例如迁移测试的遗留内容),并且HANA处于同步状态,例如,使用systemReplicationStat......
  • 数据库_duckdb_本地访问远程数据_ aws s3
    Extensions扩展FullTextSearchHTTPFSJSONPostgresScannerSQLiteScannerpython3-c"importduckdb;duckdb.query('INSTALLhttpfs;');"Loadinganextensionfromlocalstorage 参考https://duckdb.org/docs/extensions/overviewh......
  • python 连接数据库
    使用pymysql连接数据库importpymysqlconn=pymysql.connect(host="10.00.0.00",port=31379,user="root",password="123456",database="acc_test")#模拟从数据库获取单个字段值withconn.cursor()ascursor:#获取【......
  • c# winform Socket多文件传输并把传输文件保存到Oracle数据库Blob字段里
    服务器接收端代码:usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Text;usingSystem.Windows.Forms;usingSystem.Net;usingSystem.Threading;usingSystem.......
  • 查询出数据库中char型字段的最大值,查出数据库中字段最大值,max,缺少列,xh...
    SELECTmax(cast(xhasint))asxhFROMkk.kkcltj用cast(xhasint)把varchar(2)的类型转成int后再查出最大值注意:xh的字段里只能存储char型或number型数据,否则会报无效符号错误有时候不主意会写成SELECTmax(cast(xhasint))FROMkk.kkcltj这样select出来的值就没有......
  • 基于chatGPT的问答机器人开发-qdrant向量数据库的集合功能封装
    之前一直再开发基于GPT的问答知识库机器人,主要是靠qdrant的向量搜索,搜索出相关的条目,然后发送给GPT回答qdrant向量数据库有集合的概念,相当于表,每个集合里面可以创建多个向量数据。那么针对集合的操作就是下面这样的,集合列表,创建集合,删除集合 集合列表接口:http://127.0.0.1:80......
  • Linux安装配置达梦数据库教程
    1.安装规范:为方便之后统一运维管理,现规定以下信息:安装包和密钥存放目录:/boban安装目录:/home/dmdba/dmdbms数据目录:/dbdata/dmdata挂载目录:/mnt2.数据安装工作:数据库安装准备工作:创建组:[root@localhost/]#groupadddinstall创建用户:[root@localhost/]#useradd-gdinst......
  • Oracle数据库中SYS、SYSTEM、DBSNMP、SYSMAN四用户的区别
    Oracle数据库中SYS、SYSTEM、DBSNMP、SYSMAN四用户的区别SYS用户:SYS,默认密码为CHANGE_ON_INSTALL,当创建一个数据库时,SYS用户将被默认创建并授予DBA角色,所有数据库数据字典中的基本表和视图都存储在名为SYS的方案中,这些基本表和视图对于Oracle数据库的操作时非常重要的。为了维护......