杂谈--从基数评估来看问题1

前段时间遇到很多例统计信息更新不及时导致执行计划较差引发性能问题的情况,现在总结分析下,与各位分享。

问题描述:

订单表用于存放用户订单信息,其中有字段DT存放订单的创建时间,PID存放用户编号,根据业务需求,我们分别创建在列DT上索引IDX_DT,在PID上创建索引IDX_PID,我们通常会在业务低峰期进行索引维护和统计更新,在双11期间,订单暴增而统计信息没有得到及时更新,部分查询选用了不合适的索引,导致性能较差。

问题演示:

首先我们生成100W的数据,并将统计更新到最新。

DROP TABLE TB001
GO
CREATE TABLE TB001
(
    ID INT IDENTITY(1,1) PRIMARY KEY,
    PID INT DEFAULT 0,
    DT DATETIME DEFAULT GETDATE(),
    CT CHAR(500) DEFAULT ‘0‘
)
GO
--导入100W数据
INSERT INTO TB001(CT)
SELECT TOP(20000) T2.name FROM sys.all_columns T2
CROSS JOIN sys.all_objects T1
GO 50
--更新DT字段
UPDATE TB001
SET DT=DATEADD(MINUTE,ID,GETDATE()),
    PID=ID%100000
GO

--创建索引
CREATE INDEX IDX_PID
ON TB001(PID)

CREATE INDEX IDX_DT
ON TB001(DT)
GO

查看PID上统计信息

DBCC SHOW_STATISTICS(‘TB001‘,‘IDX_PID‘)

查看DT上的统计信息

DBCC SHOW_STATISTICS(‘TB001‘,‘IDX_DT‘)

然后模拟新增15W数据,新增的数据的创建时间均大于统计生成的时间。

INSERT INTO TB001(PID,DT,CT)
SELECT
RID%100000,
DATEADD(MINUTE,1000000+RID,GETDATE()),
name
FROM(
SELECT
ROW_NUMBER()OVER(ORDER BY name) AS RID,
name
FROM (
    SELECT TOP(150000) T2.name FROM sys.all_columns T2
    CROSS JOIN sys.all_objects T1
) AS T3
) AS T4

查看最后5w订单的时间

SELECT MAX(DT) AS MAX_DT,
MIN(DT) AS MIN_DT
FROM
(
SELECT TOP(50000) *
FROM TB001
ORDER BY id DESC
) AS T1

虽然在订单表中新增了15W订单呢,但是这15万订单被平均分摊,每个用户只新增1.5个订单,每个用户平均有11.5个订单,因此如果要查询2016-09-29 14:39:52.973到2016-11-03 07:58:52.973期间某个用户的订单的话,走IDX_PID会是最佳选择,但执行计划选择了IDX_DT的索引。

--表 ‘TB001‘。扫描计数 1,逻辑读取 150109 次,物理读取 0 次,预读 0 次,
--lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
SELECT * FROM TB001
WHERE DT>‘2017-01-11 19:03:46.460‘
AND DT<‘2017-02-15 12:22:46.460‘
AND PID=10

如果我们强制执行计划走索引:

--表 ‘TB001‘。扫描计数 1,逻辑读取 324 次,物理读取 0 次,预读 0 次,
--lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
SELECT * FROM TB001 WITH(INDEX=IDX_PID)
WHERE DT>‘2017-01-11 19:03:46.460‘
AND DT<‘2017-02-15 12:22:46.460‘
AND PID=10

或修改查询,避免使用索引IDX_DT:

--表 ‘TB001‘。扫描计数 1,逻辑读取 324 次,物理读取 0 次,预读 0 次,
--lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
SELECT * FROM TB001 WITH(INDEX=IDX_PID)
WHERE DT+0>‘2017-01-11 19:03:46.460‘
AND DT+0<‘2017-02-15 12:22:46.460‘
AND PID=10

--=====================================================================

在SQL SERVER 2014之间版本中,对于超出统计信息范围的参数,基数评估认为其不存在,评估行数为1。在Demo中,由于DT的两个参数均不在统计信息IDX_DT的直方图范围内,认为满足DT条件的数据为1,因此认定为使用IDX_DT索引为最优。

此类问题针对的是递增类型的数据,如自增ID,创建时间,货物批号等,随着时间推移,新增的数据总是超出统计信息的范围,当查询这些新增数据并且执行计划重新生成时,就可能导致执行计划出现问题,这也是我们常说的“统计信息未及时更新导致执行计划问题”。

--=====================================================================

解决办法:

1. 对递增类数据提高统计的更新频率(更新频率过快也是问题啊)

2. 升级到2014版本(在CdinalityEstimationModeVersion=120下,会采用新的预估算法,不过谁无事玩升级啊)

3. 使用查询提示强制使用索引(是个办法,一般也不这么玩)

4. 修改SQL(我目前采用的办法,使查询无法使用索引IDX_DT)

--====================================================================

很早拜读过群里一位大神Fanr_Zh的博客《SQL Server 2014新特性——基数评估(白皮书阅读笔记)》,感悟颇多,结合最近遇到的一些性能问题,弄个Demo与各位看官一起学习下!再次拜谢下Fanr。

--====================================================================

时间: 2024-10-09 22:01:26

杂谈--从基数评估来看问题1的相关文章

SQL Server中关于基数估计如何计算预估行数的一些探讨

关于SQL Server 2014中的基数估计,官方文档Optimizing Your Query Plans with the SQL Server 2014 Cardinality Estimator里有大量细节介绍,但是全部是英文,估计也没有几个人仔细阅读.那么SQL Server 2014中基数估计的预估行数到底是怎么计算的呢? 有哪一些规律呢?我们下面通过一些例子来初略了解一下,下面测试案例仅供参考,如有不足或肤浅的地方,敬请指教! 下面实验测试的环境主要为SQL Server 201

SQL Server调优系列玩转篇(如何利用查询提示(Hint)引导语句运行)

前言 前面几篇我们分析了关于SQL Server关于性能调优的一系列内容,我把它分为两个模块. 第一个模块注重基础内容的掌握,共分6篇文章完成,内容涵盖一系列基础运算算法,详细分析了如何查看执行计划.掌握执行计划优化点,并一一列举了日常我们平常所写的T-SQL语句所会应用的运算符.我相信你平常所写的T-SQL语句在这几篇文章中都能找到相应的分解运算符. 第二个模块注重SQL Server执行T-SQL语句的时候一些内幕解析,共分为5篇文章完成,其中包括:查询优化器的运行方式.运行时几个优化指标值

找工作经历心得总结

这几天还是没有找到实习工作,觉得实际上自己还有很多事是还没有拎清除,所以得静下来好好做个总结反思. 首先是没有给自己准确定位.这个主要原因是自己的技术不过关也是很难给自己定位.学习的时候其实自己多少有些畏难情绪,所以对于很多都是"浅尝辄止",对于没有深入研究过的东西我都不敢说自己了解,毕竟技术这种东西都是深层次的,尤其IT,还是日新月异.在学习阶段自己还有个很大的问题就是不管在时间还是任务上都没有合理的规划,每次都是东一块西一块,导致结果也是东丢一块西掉一块的. 再者也就是没有合理规划

理解SQL Server的查询内存授予(译)

此文描述查询内存授予(query memory grant)在SQL Server上是如何工作的,适用于SQL 2005 到2008. 查询内存授予(下文缩写为QMG)是用于存储当数据进行排序和连接时的临时中间数据行.查询在实际执行前需要先请求保留内存,所以会存在一个授予的动作. 这样的好处是提高查询的可靠性和避免单个查询占用所有的内存. SQL Server在收到查询时,会执行3个被定义好的步骤来返回用户所请求的结果集. 1.生成编译计划.它包括各种逻辑指令,如怎么联接数据行. 2.生成执行计

MySQL 5.6 Reference Manual-14.6 InnoDB Table Management

14.6 InnoDB Table Management 14.6.1 Creating InnoDB Tables 14.6.2 Moving or Copying InnoDB Tables to Another Machine 14.6.3 Grouping DML Operations with Transactions 14.6.4 Converting Tables from MyISAM to InnoDB 14.6.5 AUTO_INCREMENT Handling in Inn

总有一种SQL执行计划绑定方式合适你

需要绑定SQL执行计划常见的几种情况: SQL执行计划突变,导致数据库性能下降,从历史执行计划找一个合理的,进行绑定. SQL无法使用更优的执行计划,且无历史执行计划,可通过hint手工构造的方式,进行绑定. 某些Bug引起优化器生成较差的执行计划.在bug修复前,进行绑定. ORACLE固定执行计划的3种方式: Oracle 9i使用outline (可跨版本10,11g均可使用) Oracle 10g使用sql profile (11g也可使用) Oracle 11g使用sql plan m

MySQL 5.6 Reference Manual-14.4 InnoDB Configuration

14.4 InnoDB Configuration 14.4.1 InnoDB Initialization and Startup Configuration 14.4.2 Configuring InnoDB for Read-Only Operation 14.4.3 InnoDB Buffer Pool Configuration 14.4.4 Configuring the Memory Allocator for InnoDB 14.4.5 Configuring InnoDB Ch

Redis学习笔记13Redis数据类型之(6)HyperLogLogs类型

1.1.1. pfadd 向指定的hyperloglog中添加一个或多个元素.hyperloglog中重复的元素将被合并成一个元素. 语法: PFADD key element [element ...] 参数: key: 键名,键值为一个hyperloglog对象. element:待添加的元素. 返回值: 1:hyperloglog的基数评估变化了. 0: 没有变化. 例子: redis.coe2coe.me:6379> pfadd myhpp green blue yellow (inte

DT时代,手机厂商价格战或致京东意外“受伤”

昨日,魅蓝2在天猫独家首发,而差不多一周时间以前大神Note3曾与淘宝众筹合作过盲订式首发,此外此前的荣耀4C.大神F2全网通.魅族Note2. 魅族MX5等机型也都是在天猫首发.对于这个情况其实应该引起京东的重视,部分厂家态度的转变折射出一个"隐患"问题. 手机厂商价格战导致千元机市场竞争愈发激烈,拼价格成为拼销量的大前提.以目前的各厂商高配低价的千元机机型来看,放在任何平台上都不愁销售问题,但为何荣耀.大神.魅族等厂商都选择了重点关照天猫平台,而不是将赌注重点押在3C上有多年积累的