RDS SQL Server - 最佳实践 - 高CPU使用率系列之数据类型转换

摘要

前两篇文章讨论了导致CPU高使用率的两个重要原因是索引缺失和索引碎片,本系列文章之三讨论数据类型隐式转换话题。

场景分析

在SQL Server中,比较运算符(大于、小于、等于或者连接)两端的数据类型需要保持一直才能进行。否则,SQL Server会按照数据类型优先级由低到高进行隐式转化,然后再进行比较。这个行为可以通过执行计划中的CONVERT_IMPLICIT关键字看出来,后面的测试例子中,我们可以清楚的看到这一点。如果很不幸,导致SQL Server正式表字段数据类型隐式转换会带来几个方面的问题:
 数据经过了转换,所以执行计划无法走更优的Index Seek,进而选择Index Scan
 由于Index Scan,所以I/O消耗很高
 数据类型转换计算和I/O飙高,导致CPU使用率很高
SQL Server数据类型转化参照表如下图(图片来自微软官网):

解决问题

在这里,我们将这个例子详细分解为五个小步骤:
 测试环境:搭建简单的测试环境。
 执行查询:SQL Server会隐式转换正式表字段中的数据为INT类型
 数据类型隐式转换:数据类型隐式转换的表现形式
 解决问题:修改查询语句比较运算符右边的数据类型为字符串格式
 效率对比:查询修改前后的性能对比

测试环境

我们在本系列文章之一RDS SQL Server - 最佳实践 - 高CPU使用率系列之索引缺失创建的测试表上稍作修改:删除索引 => 修改字段ItemID为VARCHAR数据类型 => 创建索引。代码如下:

USE TestDb
GO

--===Drop index included
DROP INDEX IX_UserID_OrderDate_@ItemID_@OrderQty_@Price
ON dbo.SalesOrder;
GO

--===Change Data type for Testing Data convertion
ALTER TABLE dbo.SalesOrder
ALTER COLUMN ItemID VARCHAR(8) NOT NULL
GO

--=== Create Indexes
CREATE INDEX IX_ItemID_UserID_OrderDate_@OrderQty_@Price
ON dbo.SalesOrder([ItemID],[UserID],[OrderDate])
INCLUDE ([OrderQty], [Price])
WITH (FILLFACTOR = 85);
GO

EXEC sys.sp_help 'dbo.SalesOrder'
GO

从结果展示来看,ItemID已经变成了VARCAHR数据类型,展示如下:

执行查询

现在我们执行下面的查询语句,打开实际执行计划,注意WHERE ItemID = 250子句,等号右边的数据类型为INT,相比左边的数据类型VARCHAR优先级要高。所以,SQL Server必须先隐式转换正式表中该字段存储的所有数据为INT以后,再与250比较。这个转换操作会导致I/O飙高,无法使用索引和CPU使用率走高。

USE TestDb
GO
SET STATISTICS TIME ON
SET STATISTICS IO ON

SELECT
    ItemID, OrderQty, Price
FROM dbo.SalesOrder
WHERE ItemID = 250
    AND OrderDate >= DATEADD(MONTH, -1, GETDATE())
    AND OrderDate <= GETDATE();

SET STATISTICS TIME OFF
SET STATISTICS IO OFF

从性能指标页面来看,I/O为14950,CPU消耗327毫秒,时间消耗362毫秒,截图如下:

数据类型隐式转化

我们可以从执行计划中的CONVERT_IMPLICIT关键字看出,SQL Server做了数据类型的隐式转换,并且转换的是正式表中的数据。执行计划截图如下:

解决问题

问题分析清楚了,解决问题的方便变得非常简单。我们只需要保证比较运算符两端的数据类型一致,不让SQL Server隐式转换正式表字段中的数据,这样就可以大大减少I/O和CPU开销了。所以,我们把WHERE ItemID = 250子句修改为WHERE ItemID = '250'即可,修改后的查询如下:

USE TestDb
GO
SET STATISTICS TIME ON
SET STATISTICS IO ON

SELECT
    ItemID, OrderQty, Price
FROM dbo.SalesOrder
WHERE ItemID = '250'        --correct here to ItemID = '250'
    AND OrderDate >= DATEADD(MONTH, -1, GETDATE())
    AND OrderDate <= GETDATE();

SET STATISTICS TIME OFF
SET STATISTICS IO OFF

性能指标页面显示I/O消耗为61,CPU消耗为16毫秒,执行时间消耗为190毫秒,截图如下所示:

修改查询后的执行计划,走到了Index Seek,没有了CONVERT_IMPLICIT关键字的存在。执行计划截图如下:

性能对比

我们将修改查询语句前后的性能指标数据对比一下,执行时间提高了47.51%,CPU消耗提高了95.1%,I/O消耗提高了99.6%,平均性能提高了80.74%。对比数据做图如下:

总结

SQL Server做正式表字段数据类型隐式转换是导致高CPU使用率的另一重大原因,这篇文章详细分析了导致的原因、表象和解决问题的办法,指导我们平时在写查询语句的时候,需要时刻牢记比较运算符两端的数据类型保持一致。

引用文章

Data Type Conversion

时间: 2024-10-29 21:43:44

RDS SQL Server - 最佳实践 - 高CPU使用率系列之数据类型转换的相关文章

RDS SQL Server - 最佳实践 - 高CPU使用率系列之二索引碎片

摘要 上一篇文章分析了高CPU使用率的原因之一是索引缺失,接下来本系列文章之二的"索引碎片"是CPU高使用率的又一常见的原因.解决索引碎片问题是解决SQL Server服务响应缓慢,查询超时的又一利器. 问题引入 "鸟哥,我上一篇文章分享了因为索引缺失导致CPU高使用率的话题,反响不错.接下来,我打算分享索引碎片导致CPU高使用率的话题.",菜鸟主动找到老鸟汇报工作. 上一篇文章详情参见链接:RDS SQL Server - 最佳实践 - 高CPU使用率系列之索引缺

RDS SQL Server - 最佳实践 - 高CPU使用率系列之索引缺失

摘要 CPU高使用率往往会导致SQL Server服务响应缓慢,查询超时,甚至服务挂起僵死,可以说CPU高使用率是数据库这种后台进程服务的第一大杀手.本系列文章之一的"索引缺失"就是CPU高使用率的最常见的原因之一. 问题引入 "鸟啊,我们平时在服务阿里云RDS SQL Server客户的过程中,遇到最多的一个问题就是,客户反馈RDS SQL Server数据库CPU使用率很高(有时超过90%,甚至到100%),导致查询缓慢甚至超时,这类问题要如何解决啊?".老鸟已

RDS SQL Server - 最佳实践 - 高CPU使用率系列之非SARG查询

摘要 阿里云RDS SQL Server客户遇到最多的一个问题便是高CPU使用率导致导致SQL Server服务响应缓慢,查询超时,甚至服务挂起僵死.本系列文章第四篇分析非SARG查询导致CPU的高利用率的解决之道. 问题引入 "鸟啊,你听说过RDBMS的非SARG查询语句吗?我还是今天第一次听说呢!".老鸟有些不解的问菜鸟. "哈哈,鸟哥,孤陋寡闻,土鳖了吧.它可是导致RDBMS数据库CPU高使用率的又一个重要的原因呢!今天就让我细细道来.",菜鸟开始得意忘形起来

SQL Server - 最佳实践 - 参数嗅探问题

title: SQL Server - 最佳实践 - 参数嗅探问题 author: 风移 摘要 MSSQL Server参数嗅探既是一个涉及知识面非常广泛,又是一个比较难于解决的课题,即使对于数据库老手也是一个比较头痛的问题.这篇文章从参数嗅探是什么,如何产生,表象是什么,会带来哪些问题,如何解决这五个方面来探讨参数嗅探的来龙去脉,期望能够将SQL Server参数嗅探问题理清楚,道明白. 什么参数嗅探 当SQL Server第一次执查询语句或存储过程(或者查询语句与存储过程被强制重新编译)的时

SQL Server · 最佳实践 · 参数嗅探问题

摘要 MSSQL Server参数嗅探既是一个涉及知识面非常广泛,又是一个比较难于解决的课题,即使对于数据库老手也是一个比较头痛的问题.这篇文章从参数嗅探是什么,如何产生,表象是什么,会带来哪些问题,如何解决这五个方面来探讨参数嗅探的来龙去脉,期望能够将SQL Server参数嗅探问题理清楚,道明白. 什么参数嗅探 当SQL Server第一次执行查询语句或存储过程(或者查询语句与存储过程被强制重新编译)的时候,SQL Server会有一个进程来评估传入的参数,并根据传入的参数生成对应的执行计划

RDS SQL Server - 专题分享 - 巧用执行计划缓存之索引缺失

title: RDS SQL Server - 专题分享 - 巧用执行计划缓存之索引缺失 author: 风移 摘要 执行计划缓存是MSSQL Server内存管理十分重要的部分,同样如何巧用执行计划缓存来解决我们平时遇到的一系列问题也是一个值得深入研究的专题.这篇文章是如何巧用执行计划缓存的开篇,分享如何使用执行计划缓存来分析索引缺失(Missing Indexes). 问题引入 缺失索引是SQL Server CPU使用率居高不下的第一大杀手,也是SQL Server数据库非常大的潜在风险点

RDS SQL Server - 专题分享 - 巧用执行计划缓存之数据类型隐式转换

摘要 SQL Server数据库基表数据类型隐式转换,会导致Index Scan或者Clustered Index Scan的问题,这篇文章分享如何巧用执行计划缓存来发现数据类型隐式转换的查询语句,从而可以有针对性的优化查询,解决高CPU使用率的问题. 问题引入 测试环境 为了更好的展示从执行计划缓存缓存中找出导致数据类型转化的查询语句,我们先建立测试环境. -- Create testing database IF DB_ID('TestDb') IS NULL CREATE DATABASE

RDS SQL Server - 专题分享 - 巧用执行计划缓存之Single-used plans

背景引入 执行计划缓存是SQL Server内存管理中非常重要的特性,这篇系列文章我们探讨执行计划缓存设计中遇到的single-used plans问题,以及如何发现.如何定性和定量分析single-used plans带来的影响,最后我们使用两种方法来解决这个问题. 什么是Single-used Plans 要解释清楚什么是Single-used Plans,首先需要解释SQL语句执行计划缓存是什么?SQL Server执行每一条SQL语句之前,会从执行计划缓存内存中查看是否存在本条语句的执行

开启TDE的RDS SQL Server还原到本地环境

问题引入 阿里云RDS SQL Server 2008 R2版本,客户在前端控制台可以自行启用透明数据加密(TDE),来避免客户数据库备份文件被非法盗取而引起拖库风险.最近,客户咨询如何将开启了TDE的数据库还原到本地环境,这篇文章的目的就是为了解决这个问题. 前提条件 请仔细阅读以下限制条件,缺一不可.  版本限制:仅针对RDS SQL Server 2008 R2版本.  启用了TDE:客户在前端控制台启用了TDE并且任务已经完成(一旦启用,无法再次关闭TDE).  备份文件:下载的备