索引笔记(二)

六:索引建立的一般性原则:
为了确保select语句的无效处理不是由于缺少索引而造成的,我们需要按每列或列的组合来创建索引,如果仅希望select语句,这回是一种较好的方法。但是,这种解决方案会带来许多问题。而不只是索引的存储的代价,另一个重要的原因是每次更新(增、删、改)均要求相应的索引更新从而降低了处理速度。因此,对于索引的建立必须这种的处理。

1)在候选键上建立唯一索引
在create table时,可以指定主键和交换键。结果是在相关的列中将不会包含重复的值。这里索引建立在每个候选键上,以便新值的唯一性可快速的检索。sql会自动的在候选键上创建唯一索引。

2)在外键上建立索引
如果在链接列上未建立索引,则连接执行的时间会很长。对于部分连接,连接列也是涉及表的键。可以是主键候选键或是外键。根据原则我们应在外键上建立索引

3)选择规则中包含的列的索引
仅在选择的行数只占表中总行数的一小部分时,使用索引才会节省时间。对于何时需要定义索引而何时又不需要定义索引,这取决与几个因素:最重要的是表中的行数(表的重要性)、所涉及列中不同值的个数(列的重要性)以及列中的值的分布。
示例:
语句1:
Select count(*)
From players_xxl
Where initals='in1'        说明:在该表中initals列仅包含两个不同的值,即:‘in1’‘in2’。(这一点很重要,说明该查询语句包含一个低重要性的列条件)

语句2:
Select count(*)
From players_xxl
Where postcode = 'p25'      说明:列postcode包含50个不同的值  (说明该语句包含一个有着平均重要性的列条件)

语句3:
Select count(*)
From players_xxl
Where  street = 'street164'     说明:列street每个值最多出现10次   (说明该语句包含一个有着高重要性的列条件)

测试说明:每条select语句已三个不用大小的players_xxl表上执行:小(100 000行)、中(500 000行)、大(1 000 000行)。三条语句中的每一条运行在6种不同的环境中,每条语句在一种环境中运行多次。

从测试结果中推导出的规则:
A)表越大,索引的影响越大。表是否大到足够值的定义一个索引,这取决于具体的应用。
B)索引对低重要性列(不同值很少)的影响最小。语句2随着表的增大,处理速度有所增强,但增幅很小。但对于语句3,则完全相反,这里,索引是对处理速度的主要影响,而且随着表的变大,这种区别也愈加的明显。
C)是否定义索引的第三个因素是一列内的值的分布。在上面的几条语句中,涉及的每列的值的分布差不多,每个值在列中出现多次。如果不是这种情形,那么结果如何? 看下面的示例语句:
语句 4.
Select count(*)
From players_xxl
Where sex = 'M'

语句5.
Select count(*)
From players_xxl
Where sex = 'F'

对于这个测试,sex列中值的分布如下:M值出现在95%的行中,F值出现在5%的行中,这是个不相等分布的极端示例,可清晰的看出其不同。我们可以看出语句4索引的影响比较起语句5要小的多了。如果定义了索引,则在大表players_xxl中统一所有女运动员的人数的速度会较之前快180倍。

4)在列的组合上建索引
如果where从句包含一个and运算符,那么通常要将索引建立在列的组合上,以确保处理更有效率
示例:
Select *
From players
Where name = ‘colline’and   initials = 'DD'

相关的索引为:
Create index nameindex  on  players(name, initials)

在某些情形下,在我们执行这样的一条select语句时,仅对一列进行索引就够了。假设重复的名字很少出现在name列中,且该列是唯有索引的列,通常,sql将找到满足条件name=‘colline’的所有行,方法是使用这个索引,它并不会检索出许多行,这时,列的组合上的索引与需求相比,将会占据更多的存储空间,因而不能增强select语句的处理。定义在列的组合上的索引也可用于其中仅指定了索引的第一列(或几列)的选择中。

5)在用于排序的列上建立索引
如果sql需要对select语句的结果按没有建立索引的一列进行排序,则必须执行单独的(且耗时的)排序处理。这个额外的排序操作是可以避免的,方法就是在相关的列上定义一个集群索引。当使用from从句从数据库中提取行时,可使用该索引,from从句的中间结果已按正确的列排序,此后就不需要排序了。这个规则仅在涉及的列不包含许多null值(因null值是不会在索引中排序的)且select语句不带有可被优化的where从句时才有效。何时sql执行排序? 如果在select语句中添加order by 从句,那么sql会执行排序。此外,当列被组合在一起时(使用group by),所有的行必须首先排序。在行已被排序的情况下,sql会更快的处理group by 从句。如果select从句中使用distinct,则所有的行必须排序,以确定它们是否是相等的。因此,排序规则再次适用:当行已被排序时,sql可更快的处理distinct

注:在同一列或列的组合上定义两个索引是没有意义的。

七:特殊的索引形式
长期以来sql的产品仅支持B树索引,近来增加了其他的索引形式,主要原因在于增强数据仓库的通用性,这里介绍5种索引形式:多表索引、虚拟列索引,选择列索引以及位图索引。
注:并不是所有的sql产品均支持这些新的索引形式。如:mysql不支持

1)多表索引
在前面提到的索引都是在同一个表中的列上定义的。对于多表索引(也称为链接索引),这种限制将不在适用,多表索引可使我们在两个或多个表的列上建立索引,示例如下:
在players, matches表的playerno列上定义一个多表索引
Create  index   play_matc   on   players(playerno), matches(playerno)  
这个多表索引的优点是:如果两个表使用一个至playerno的连接链接在一起,则该链接可被快速的处理。这是添加这种索引的主要原因。
注:为多表索引创建的索引树仍然是B树索引。唯一的区别在于存储在叶数据页中的内容。

2)虚拟列索引
这种类型的索引不是在一整列上建立一个索引,而是在一个表达式上定义一个索引。
示例:在matches表中,根据表达式(won - lost)/2的结果创建一个虚拟列索引
Create  index   mat_cont   on  matches((won - lost)/2)

代替在索引树中对列的值进行排序,首先为该表的每行计算表达式的值,结果记录在索引树中,索引树中的值指向表达式的值等于该值的行,
要注意:在索引定义中使用的表达式存在某些限制:聚合函数和子查询是不允许的。
优点:增强了其中在where从句中使用了相关表达式语句的处理速度,例如:
Select *  from matches  where (won - lost)/2  >1
虚拟列索引的索引树也是B树索引。主要区别是在于存储在索引树中的值均不出现在表本身中。

3)选择索引
选择索引和一般的基于B树的索引相比,主要有如下区别:选择索引仅选择一部分行。假设:matches表中有上千万级的数据行,而多数的用户主要对近两年的数据有兴趣,而近两年的数据仅占表中的200 000行。在用户在查询中包括数据不早于2年的条件。其他的用户是需要全部的数据的。对于索引,行数越多,索引树就越大,速度也就越慢。所以我们可以有选择的对近两年的数据建立索引(200 000行数据)
建立的语句如下示例:
Create   index   pen_pp   on   penalties     where    payment_date >  '1990-12-31'                   // penalties 为表名
注:where从句用于指出表中的哪些行需要被索引。在这用情形下,优化程序必须聪明到不仅可以为请求涉及1996年后的罚款信息的语句使用索引,而且必须可以直接访问表来提取那些未索引的行。

4)散列索引
散列索引不是基于B树,但散列索引和B树索引有某些共性:直接访问表中的行的可能性。其主要的区别是:1)散列索引不会创建索引树。2)散列索引必须在表被填充前被创建,也就是说表已经存在,但没有数据。
创建了一个散列索引后,会自动保留一定的磁盘空间,散列空间的大小由散列索引的大小决定,并在创建散列索引时指定,创建散列索引的示例如下:
Create  hash  index   index_name  on   table_name(col_name)   with  pages=100
该语句为table_name表分配了100个数据页的散列空间。
在创建一个散列索引时也同时牵涉到散列函数的开发。
使用的原理简述如下:在使用INSERT语句添加一个新行时,数据库在幕后通过散列计算地址,且该行存储在相关的数据页中,在使用select语句检索一个记录时(where子句使用的条件列上建有散列索引),也会用到散列函数。通过散列函数,数据库可以立刻计算出符合条件的记录所在的数据页及所在的行,如果该行没有出现在这个数据页中,则标明这个表中没有这条记录。所以,散列索引要快于B树索引。B树索引会在找到实际的行前浏览整个索引树。
缺点:
1)如果散列列中的值分布均匀,则散列空间中的数据页也会比较均匀填充(例如:一个表的ID字段每插入一条记录,则该字段自增1,那么这个列上的值就会很均匀),如果散列函数在散列空间上不能均匀分布,则某些散列数据页可能非常空,则其他的数据页可能非常的空。因此,语句的执行时间可能会有很大的差别。
2)如果数据页未平均分布,则某些数据页将不能正确的填充,这会导致浪费存储空间
3)数据页占有很大的存储空间,因此它可能是满的。当散列函数为另一个新数据页返回这个满的数据页时,则数据库会使用一个从第一个数据页指向第二个数据页的指针来创建一个链式数据页。链式数据页越多,速度就会越慢。
4)散列空间充满以后,必须创建新的散列空间。尽管所有的数据库产品均提供特定的语句或程序来做这件事,但是散列空间的增加会涉及到许多的工作,必须从表中取出所有行,新空间必须准备就绪,新的散列函数必须被创建(因为有更多的数据页),最后所有的行必须再放到散列空间中。如果表的数据量比较小,那么这些步骤会很快的完成,如果表的数据量很大,那就会相当的耗时了。所以这就导致散列索引环境相当的静态。

5)位图索引
上面提到的索引类型都可以加快处理速度,但同时存在一个问题:一个列中包含的重复的值越多,上面提到的索引类型的优点就越少。例如对于表中的sex列的索引不会对select的性能产生明显的提升。所以对于许多数据库产品,首要的原则是,如果查询一个表中的15%以上的行,则表的串行浏览要快于使用索引的直接访问。为了解决这类问题,有些数据库厂家在其sql产品中增加了位图索引来增强性能。
创建位图索引的示例如下:
Create bitmap  index   index_name   on   table_name(col_name)
特点:列中的重复值越多,B树索引的速度越慢,位图索引的速度越快
缺点:降低更新数据的速度并会占用存储空间。位图索引很少或从不会用在事务环境中。

你可能感兴趣的:(sql,mysql,F#)