SQL Server 索引的最佳实践
索引设计是数据库设计中比较重要的一个环节,对数据库的性能其中至关重要的作用,但是索引的设计却又不是那么容易的事情,性能也不是那么轻易就获取到的,很多的技术人员因为不恰当的创建索引,最后使得其效果适得其反,可以说“成也索引,败也索引”
本系列文章来自Stairway to SQL Server Indexes,翻译和整理发布在agilesharp和博客园,希望对广大的技术朋友在如何使用索引上有所帮助。
在本篇文章中,我们在学习了之前的知识之后,推荐14条指导方针。这14条指导方针可以帮助你更好的为数据库构建索引。
本篇文章的格式使用了由Addison Wesley出版社出版的<Framework Design Guidelines>中使用的格式。每一个最佳实践之前都使用了如下4个动词:要,考虑,避免、不要,分别代表如下意思:
要(Do):这个原则要坚决遵守
考虑(Consider):通常情况下都要遵循这个原则,但如果你对原则背后的原理有了深入了理解,可以根据实际情况不采用这个原则
避免(Avoid):考虑的反义词,意味着避免做某这类事,但同样,如果你了解了背后的原理,则可以根据实际情况做这类事。
不要(Do Not):避免的增强版,意思是无论什么时候都不要做这类事。
指导方针
要了解跑在数据库上的应用程序/用户
使用索引的主要目的是为了提高跑在数据库上应用程序读取和操作数据的速度,如果你不知道程序主要对数据库进行什么操作,索引优化就无从谈起。
当然,如果你全程参与了程序的设计和开发,那再好不过。但这种情况少之又少,大多数情况都是你直接接手数据库和应用程序,这时你就需要两步走的了解你所接手的东西-通过外部和内部。
外部方法包括从用户那里了解程序相关的信息,观察他们使用程序的过程,阅读用户文档和交接文档。
内部方法是去看程序本身对数据库产生的操作。比如说Activity Monitor, Profiler等工具,也可以使用sys.dm_db_index usage_stats和sys.dm_db_missing_index_XXX系列DMV中找到所需信息,这些信息包括用的最多的查询,用的最多的索引,用的少的索引以及本应建却没有建的索引。
通过找到拖累系统性能的查询,比如报表服务中用到的语句,agent中执行的T-SQL,SSIS中执行的T-SQL以及存储过程。找到这类信息就可以知道优化该从何处下手。
得到上面的信息后,就可以知道哪些索引应当存在,哪些索引应该删除。
不要过度创建索引
过多的索引和太少的索引都不是好事。表中该有多少索引可不是一个固定的数字。当你为主键,候选键和外键建立了索引之后,剩下的索引该怎么建就需要谨慎分析后再做定夺了。
要明白这点:同样的数据库在不同的环境下要有不同的索引
在忙时或是闲时;在OLTP环境或是OLAP环境下,所需要的索引是不同的。
比如每天晚上一次性大量更新数据的报表数据库在这时只需要少量索引,而在日间忙时则需要大量索引。数据库上跑少量查询要比数据库跑大量查询需要更少的索引。
要给每个表设置主键
虽然SQL Server并不强制要求设置主键。但一个没有主键的表无论在OLTP还是OLAP环境下都是一件危险的事,因为没有主键就不能保证每行是唯一的。这时你就无法知道同一行数据是否在表中存在两条,尤其是在你还没有足够的信息去分析这点时。
尽管SQL Server不强制要求设置主键,但主键是关系数据库的一个关键理论。如果没有主键约束,那么与之关联的唯一索引或是连接操作就有可能产生意料之外的性能问题。
除此之外,很多第三方开发工具或插件也要求表有主键,比如说吧,ADO.Net的SqlCommandBuilder和Entity Data Modeler都依赖表中存在主键约束。另外,主键约束会创建一个同名的唯一索引来保证主键的唯一性。
考虑给每个表设置聚集索引
本系列第三篇关于聚集索引的文章阐述了聚集索引带来的好处。使用聚集索引表中的数据就是按聚集索引键的顺序存在而不再以堆存放。使用聚集索引的好处是使得数据按照聚集索引键的顺序存放,并使得后插入的元素依然保持这个顺序。
如果你遵循了上一个建议,那么每个表都应该有主键,因此,每一个表都应该有一个或多个索引,让其中的一个索引成为聚集索引。聚集索引本身并不会使得表上多了一个索引,而是让表的结构更好的组织。
选择聚集索引键时,要记住第六篇文章中所说的,聚集索引键应该唯一,短和尽量不需要改动。
考虑使用外键作为聚集索引键的最左列
将外键设置为聚集索引的最左列就是将表中的数据按照这列的值进行汇总和组织,这也是查询所需。比如说你用信用卡消费这个行为是和卡关联最强的的,而不是和你刷卡的商场以及处理这笔消费的银行。则将信用卡号作为消费记录表中聚集索引的最左列,使得所有同一张卡的消费信息就会存在连续的页中。
当然了,你还需要另外一个很少变动的列和这个信用卡号列组合起来保证聚集索引键的唯一性。
考虑为索引添加包含列
(译者注:这里作者文章有BUG,这段和上段一样,我就大胆的写一下原因吧。)为索引添加包含列的原因是减少对索引所在表的书签查找。因为包含列不会占用索引的非叶子节点空间,所以不会影响B树的高度,通过在叶子节点附加上一些列,使得索引更容易的“覆盖”所请求的查询,从而减少了书签查找,降低了查询成本。
但同样,使用包含列使得非聚集索引占用的空间增加了,所以使用包含列时要综合考虑。
避免为重复值很多的未过滤列创建非聚集索引
更早之前的一条建议“永远不要索引性别列”,是由于这列只会存在男性和女性两个值。当遇到WHERE Gender=的语句时使用表扫描要远远好于书签查找,查询优化器无法从这个索引中获益。
考虑为列中重复值最多的值创建过滤索引
如果某列大量的行中都存在相同的值,这个值可以是NULL,那么使用过滤索引将这个值过滤掉,剩下的值所生成的索引就会更小,小索引使得查询优化器选择书签查找而不是表扫描,SQL Server也就更容易使用索引。
考虑使用填充因子来面对未来的数据增长
假如一个表中只有几个月的数据,但这个表年底的数据已经可以估算出来时,重建索引的过程中将填充因子设置为7或8,这将使索引占用的页和年底占用的页大致相同,这可以更早的暴漏性能问题,比如说表扫描时IO的占用。
考虑使用填充因子来减少页分裂
加入表中的数据已经达到了页所能容纳的最大值。那么再插入数据就会导致页分裂了。因此重建索引时可以使用填充因子,如果数据库写大于读的话,设置填充因子为75,如果读写大致相等的话,设置填充因子为90到95.
要在创建非聚集索引之前,先创建聚集索引
与之对应的指导方针是:在删除聚集索引之前,先删除非聚集索引。如果你不按照这条方针做,则会导致无意义的重建非聚集索引。将表由聚集索引变为堆会使得表上的非聚集索引重建,因为非聚集索引的书签由聚集索引键变为RID。
要根据索引的使用频率定期整理索引碎片或是重建索引
如果一个索引经常用于扫描,正如我们在第11篇文章中所说,那么外部碎片对于性能的影响就变得非常大。这时你就需要考虑在外部碎片到达10%的时候整理索引了。当外部碎片达到30%时就需要重建索引。对于OLTP环境来说,上面的值是一个分界点,这个点就是整理或重建索引的代价小于其带来的性能提升。
要经常更新索引的统计信息
关键字是“经常”,也就是多久更新一次。通过了解跑在数据库上面的程序的负载之后,就知道该多久更新一次统计信息了。我已经在第14篇文章中讲述了为什么要定期更新索引。
总结
上面的这些最佳实践是来自多个DBA多年来实践于不同环境所产生的。遵循这些指导方针可以帮助你创建更好的的索引。
SQL Server 索引的最佳实践的更多相关文章
- SQL Server索引设计 <第五篇>
SQL Server索引的设计主要考虑因素如下: 检查WHERE条件和连接条件列: 使用窄索引: 检查列的选择性: 检查列的数据类型: 考虑列顺序: 考虑索引类型(聚集索引OR非聚集索引): 一.检查 ...
- SQL Server索引进阶:第一级,索引简介
这个并不是我翻译的,全文共有15篇,但我发现好多网站已经不全,所以自己整理. 原文地址: Stairway to SQL Server Indexes: Level 1, Introduction t ...
- 【译】索引进阶(一):SQL SERVER索引介绍
[译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正] 原文链接:http://www.sqlservercentral.com/articles/Stairway+Series/7 ...
- SQL Server索引总结二
从CREATE开始 通过显式的CREATE INDEX命令 在创建约束时作为隐含的对象 随约束创建的隐含索引 当向表中添加如下两种约束之一时,就会创建隐含索引. 主键约束(聚集索引) 唯一约束(唯一索 ...
- SQL Server 索引结构及其使用(一)
转载:SQL Server 索引结构及其使用(一) 作者:freedk 一.深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clus ...
- SQL Server 索引维护(1)——系统常见的索引问题
前言: 在很多系统中,比如本人目前管理的数据库,索引经常被滥用,甚至使用DTA(数据库引擎优化顾问)来成批创建索引(DTA目前个人认为它的真正用处应该是在发现缺失的统计信息,在以前的项目中,用过一次D ...
- SQL Server 索引结构及其使用(一)[转]
SQL Server 索引结构及其使用(一) 作者:freedk 一.深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(cluster ...
- SQL Server 索引维护:系统常见的索引问题
在很多系统中,比如本人目前管理的数据库,索引经常被滥用,甚至使用DTA(数据库引擎优化顾问)来成批创建索引(DTA目前个人认为它的真正用处应该是在发现缺失的统计信息,在以前的项目中,用过一次DTA,里 ...
- sql server 索引总结三
一.非聚集索引维护 非聚集索引的行定位器值保持相同的聚集索引值,即使该聚集索引列物理上重新定位后,也是如此. 为了优化这个维护开销,SQL Server添加一个指向旧数据页的指针,以在页面分割之后指向 ...
随机推荐
- swift语法之常量 变量 类型
常量和变量: 在swift中声明变量或者声明常量的时候可以不用写变量或者常量类型 因为系统会自动推导出对应的类型. 变量:可以更改值 swift中每句代码后面不需要加 ; 号 var num = 5 ...
- 删除ubuntu旧内核的方法
https://www.jianshu.com/p/75edb9a5fbab 磁盘满了 需要清理系统盘 1,先用uname -a 查看当前内核版本: uname -a Linux 10-9-37-13 ...
- 实现mysql的读写分离(mysql-proxy)____2
mysql-proxy简介 MySQL读写分离是指让master处理写操作,让slave处理读操作,非常适用于读操作量比较大的场景,可减轻master的压力. 使用mysql-proxy实现mysql ...
- Spring系列(2):Spring框架
一.Spring定义 Spring是一个开放源代码的设计层面框架,它解决的是业务逻辑层和其他各层的松耦合问题,因此它将面向接口的编程思想贯穿整个系统应用. Spring是于2003 年兴起的一个轻量级 ...
- adb: failed to install app-debug.apk: Failure [INSTALL_FAILED_ABORTED: User rejected permissions]
一.使用adb 的usb真机调试,安装错误: adb: failed to install app-debug.apk: Failure [INSTALL_FAILED_ABORTED: User r ...
- The Snowflake Elastic Data Warehouse
开篇说的是,Shared-nothing当前已经是主流的架构,需要用自身的local disks来存储数据,Tables被水平划分到各个partitions上 这种架构,比较适合star-schema ...
- 端口镜像——配置原理篇
镜像是指将经过指定端口(镜像端口)或者指定VLAN(镜像VLAN)的报文复制一份到另一个指定端口(观察端口),然后转发到网络监控设备,供网络管理员进行网络监控与故障管理. 看官们可以通过下面的这张图了 ...
- Python统计数据库中的数据量【含MySQL、Oracle】
Python程序文件如下: # -*- coding: utf-8 # File : start.py # Author : baoshan import json import pymysql im ...
- 【Vegas原创】MAC电脑升级系统无法开机的终极解决办法
MAC OS升级Mojave .Catalina ,老一代的MacBook会产生一种情况:无法开机.按电源键没反应,会有间断性的滋滋的声音,屏幕都不亮. 终极解决方法,就一个字:等. 我升级Mojav ...
- Sword CRC算法原理
CRC校验原理 CRC校验其根本思想a.发送端和接收端约定一个整数 bb.发送端在原始数据帧后面附加一个数 k ,产生一个新的数据帧c.接收端接收到数据帧后,对接收的数据帧和整数 b 进行位异或操作, ...