- 当SQL Server访问表中的数据时,它扫描表的所有页或者使用索引减少需要扫描的行;有时SQL Server会创建临时索引以提高查询性能,但是这样的行为不是数据库管理员或者程序员可控的行为,并且只针对单次查询;除标准类型索引外,还包括其他类型索引:
- Full Text Index:提供灵活的文本查询
- Spatial Index:为Geometry、Geography类型创建的索引
- Primary and Secondary XML Index:帮助查询XML数据
- ANSI SQL的定义中并没有描述索引,索引被认为是数据库内部实现细节,SQL Server使用索引提高性能和实现特定的约束;当你创建主键或者对列指定了唯一性约束,SQL Server自动在这些列上创建索引,这样在检测给定值是否存在时更快
- 对于列表中大量实体,树结构提供了快速查询的能力,二叉树很快会变得不平衡、不可用(因为二叉树要求每个节点只能拥有两个子节点,嵌套层次很深),SQL Server中的索引是基于自平衡形式树,即SQL Server索引中每个节点允许多个节点,这样提高了索引的效率,避免深层次的嵌套
- 设计索引时的三个重要概念:
- Selectivity可选择性:衡量相对于总行数每次查询返回的行数,可选择性越高返回的行数越少,索引设计越合理
- density密度:唯一性数据的缺乏率,即数据行的重复率,高密度意味着大量行重复,意味着索引设计不合理
- index depth索引深度:从根节点到叶子节点的级数,通常都误以为索引很深,其实不然,一般情况下,索引也就3-4层
- 索引碎片即索引没有有效使用页面,碎片都是随着数据修改产生的;对于数据读取来说,读取每一页越满,索引执行效率越高;最开始索引页都是满的,随着数据修改,会需要拆分数据页,造成索引碎片
- 内部碎片即将索引页拆分为两页,每页只有一半的数据;外部碎片即需要添加新的索引页,但是新的索引页不是按顺序添加,即添加到已有索引页后边,而是放到其他位置,这样读取的时候就不是一页一页读取,而是需要通过指针跳跃到另外一个位置读取
- 检测索引碎片工具:SSMS和sys.dm_db_index_physical_stats、avg_fragmentation_in_percent(查看碎片率)
- 数值型索引效率非常高,可选择性非常高,排序和比较操作非常快,精确数值类型效率最高,整型是效率最高的,常用的是int和bitint,近似数值类型(float、real)效率不是很高,因为他们更大、需要的比较操作更加复杂,比较结果也不准确,可能会导致非预期的结果,对他们进行操作时需要非常小心
- 字符索引也不是很高效,字符值比数值更大,因此每个索引页的条目就少,执行查询的效率就低;除非进行二进制比较,否则字符比较也慢,因为要应用一套复杂的规则决定比较的结果;字符索引也更加容易引起索引碎片,因为字符很难连续
- 日期相关类型也是非常好的索引类型,只比整型低效,相对来说较小、比较和排序非常快;date类型比datetime类型更高效,因为date的size更小
- GUID类型索引效率中等,通常都错认为他们很大,但是他们可以执行二进制形式比较,以为着他们可以很紧密的包装成索引,执行比较和排序的效率也是很快的;问题GUID是随机的,当使用他们做索引时,在进行大量的插入操作时,会产生很多的碎片,引起性能问题
- BIT类型索引和整型效率一样高,因为BIT只有两个值,通常都认为BIT类型作为索引没有用,但实际上BIT类型索引还是有用的,比如一亿行的数据,这些数据中包含一列IsCompleted,如果未完成的行非常少的话,那么将该列作为索引去查找未完成的行可选择性将非常高,如果查找完成的行的话,效率则很低,通常都用左filtered index
- 对计算列进行索引可以非常高效,可以用来帮助提高设计不好的数据库提高性能,在计算列上创建索引需要满足如下条件:
- 表达式结果必须是确定的和准确的,比如SYSDATETIME()返回的时间每次都是不一样的,就是不确定的
- ANSI_NULLS开关必须是开着的
- 不能返回text、ntext、image
- NUMERIC_ROUNDBORT需要设置为OFF
注意SQL Server的查询优化器可能会护绿计算列上的索引,即使上面的要求多满足;在SQL Server中可以持久化计算列,这样的话就不是每次查询的时候计算值,而是在插入或者更新时计算并存储,当数据经常查询很少更新时,持久化计算列很有用
- 在多个列上建立索引称为复合索引composite index,其优势包括可选择性更高、避免对输出行排序;对A、B建立索引和对B、A建立索引是不一样的,应该首先在可选性更高的列上建立索引
- 对于单个索引,升序和降序没有区别,SQL Server中索引都是双向链接的;对于复合索引则可以受益于组件不同顺序,通常都是用来避免排序的,比如你要按OrderDate升序、Customer降序查询时,如果索引也是这么构建的话,就不需要排序,查询更快
- SQL Server在优化和执行查询前,需要知道表中数据结构和索引信息,来决定使用索引还是执行全页扫描
- 需要为查询建立合理的执行计划
- 知道索引的使用性非常重要
- 可选择性是非常重要的指标