索引设计是数据库设计中比较重要的一个环节,对数据库的性能其中至关重要的作用,但是索引的设计却又不是那么容易的事情,性能也不是那么轻易就获取到的,很多的技术人员因为不恰当的创建索引,最后使得其效果适得其反,可以说“成也索引,败也索引”

本系列文章来自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 索引的最佳实践的更多相关文章

  1. SQL Server索引设计 <第五篇>

    SQL Server索引的设计主要考虑因素如下: 检查WHERE条件和连接条件列: 使用窄索引: 检查列的选择性: 检查列的数据类型: 考虑列顺序: 考虑索引类型(聚集索引OR非聚集索引): 一.检查 ...

  2. SQL Server索引进阶:第一级,索引简介

    这个并不是我翻译的,全文共有15篇,但我发现好多网站已经不全,所以自己整理. 原文地址: Stairway to SQL Server Indexes: Level 1, Introduction t ...

  3. 【译】索引进阶(一):SQL SERVER索引介绍

      [译注:此文为翻译,由于本人水平所限,疏漏在所难免,欢迎探讨指正]  原文链接:http://www.sqlservercentral.com/articles/Stairway+Series/7 ...

  4. SQL Server索引总结二

    从CREATE开始 通过显式的CREATE INDEX命令 在创建约束时作为隐含的对象 随约束创建的隐含索引 当向表中添加如下两种约束之一时,就会创建隐含索引. 主键约束(聚集索引) 唯一约束(唯一索 ...

  5. SQL Server 索引结构及其使用(一)

    转载:SQL Server 索引结构及其使用(一) 作者:freedk 一.深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(clus ...

  6. SQL Server 索引维护(1)——系统常见的索引问题

    前言: 在很多系统中,比如本人目前管理的数据库,索引经常被滥用,甚至使用DTA(数据库引擎优化顾问)来成批创建索引(DTA目前个人认为它的真正用处应该是在发现缺失的统计信息,在以前的项目中,用过一次D ...

  7. SQL Server 索引结构及其使用(一)[转]

    SQL Server 索引结构及其使用(一) 作者:freedk 一.深入浅出理解索引结构 实际上,您可以把索引理解为一种特殊的目录.微软的SQL SERVER提供了两种索引:聚集索引(cluster ...

  8. SQL Server 索引维护:系统常见的索引问题

    在很多系统中,比如本人目前管理的数据库,索引经常被滥用,甚至使用DTA(数据库引擎优化顾问)来成批创建索引(DTA目前个人认为它的真正用处应该是在发现缺失的统计信息,在以前的项目中,用过一次DTA,里 ...

  9. sql server 索引总结三

    一.非聚集索引维护 非聚集索引的行定位器值保持相同的聚集索引值,即使该聚集索引列物理上重新定位后,也是如此. 为了优化这个维护开销,SQL Server添加一个指向旧数据页的指针,以在页面分割之后指向 ...

随机推荐

  1. haproxy 2.0 dataplaneapi rest api 转为graphql docker 镜像

    为了方便直接使用haproxy dataplaneapi graphql 格式的查询,制作了一个简单的docker 镜像 基于dotenv 进行配置管理,可以直接通过环境变量传入参数,处理不同hapr ...

  2. 洛谷 P3371【模板】单源最短路径(弱化版)

    题面 既然是模板, 那就直接贴代码? 两种思路 1.迪杰斯特拉 #include <cstdio> #include <cstring> #include <iostre ...

  3. nginx 访问控制之 document_uri

    这就用到了变量$document_uri,根据前面所学内容,该变量等价于$uri,其实也等价于location匹配. 示例1: if ($document_uri ~ "/admin/&qu ...

  4. SQL回顾

    数据库的本质是一种特殊的文件 数据库是由数据表组成的,数据表是真正存储数据的 数据库客户端-->SQL语句-->数据库服务器-->数据库文件 表与表之间存在关联的数据库称为关系型数据 ...

  5. js数组reduce()方法的使用和一些应用场景

    reduce()的使用 reduce()方法为归并类方法,最常见的应用场景就是,计算数组中每一项的总和. reduce()方法会遍历数组的每一项,它接收两个参数: 第一个参数是:每次遍历都会调用的函数 ...

  6. RabbitMQ C#客户端自动重连

    重要参考文章来源:http://gigi.nullneuron.net/gigilabs/resilient-connections-with-rabbitmq-net-client/ 参考代码:ht ...

  7. Spring Cloud-新一代Web框架微服务

    序言 springcloud是微服务架构的集大成者,将一系列优秀的组件进行了整合.基于springboot构建,对我们熟悉spring的程序员来说,上手比较容易. 通过一些简单的注解,我们就可以快速的 ...

  8. Anaconda更新失败简单解决[CondaHTTPError: HTTP 000 CONNECTION FAILED for url]

    问题:conda无法安装更新,报错内容如下:参考链接:conda httperror http none none for url none Anaconda更新失败 conda create -n ...

  9. OpenCV3与深度学习实例:Dlib+VGG Face实现两张脸部图像相似度比较

    原文:https://my.oschina.net/wujux/blog/2221444 实现思路: 1.使用Dlib识别并提取脸部图像 2.使用VGG Face模型提取脸部特征 3.使用余弦相似度算 ...

  10. TortoiseGit用户名密码的更换方法介绍

    http://www.downza.cn/xy/53171.html 有时候因实际需求要更换TortoiseGit用户名密码,怎么办呢?下文就是TortoiseGit用户名密码的更换方法介绍,一起看看 ...