1. 案例

        有张表名为table的表,由三列组成,分别是姓名、性别和婚姻状况,其中性别只有男和女两项,婚姻状况由已婚、未婚、离婚这三项,该表共有100w个记录。现在有这样的查询:     select * from table where Gender=‘男’ and Marital=“未婚”;

姓名(Name)

性别(Gender)

婚姻状况(Marital)

张三

已婚

李四

已婚

王五

未婚

赵六

离婚

孙七

未婚

...

...

...

1)不使用索引

        不使用索引时,数据库只能一行行扫描所有记录,然后判断该记录是否满足查询条件

2)B树索引

        对于性别,可取值的范围只有'男','女',并且男和女可能各站该表的50%的数据,这时添加b树索引还是需要取出一般数据,因此完全没必要。相反,若是某字段取值范围很广,几乎没有重复,比如身份证号,此时使用b树索引比较合适。事实上,当取出的行数据占用表中大部分数据时,及时添加了b树索引,数据库如oracle,mysql也不会使用b树索引,很有可能还是一行行全部扫描。

2. 位图索引出马

一共8条数据,那么就产生2个字符串,一个代表男,一个代表女,字符串长度为数据的总数量,字符串的值:第一位(如果第一条数据是男就是1,若不是就是0),第二位,第三位,以此类推。由此就生成了长度为总数量,只包含01的字符串,通过这个字符串就能知道第几条数据是男,第几条不是男;同理,另一条代表女的字符串也一样,是女的就是1,不是则为0

查询的列的基数非常小,只有几个固定值,如性别、婚姻状况,行政区等等。要为这些基数值比较小的列建索引,就需要建立位图索引。

男向量为10100...,向量的每一位表示该行是否是男,如果是则为1,否为0,同理,女向量为01011...

RowId

1

2

3

4

5

...

1

0

1

0

0


0

1

0

1

1


        对于婚姻状况这一列,位图索引生成三个向量,已婚为11000... ,未婚为00100...,  离婚为00011...。

RowId

1

2

3

4

5

...

已婚

1

1

0

0

0


未婚

0

0

1

0

1


离婚

0

0

0

1

0


        当我们使用查询语句“select * from table where Gender=‘男’ and Marital=“未婚”;”的时候,搜先取出男向量10100...,然后取出未婚向量00100...,将向量做and操作,这时生成新向量00100...,可以发现第三位为1,表示该表的第三行数据就是我们需要查询的结果。

RowId

1

2

3

4

5

1

0

1

0

0

and






未婚

0

0

1

0

1

结果

0

0

1

0

0

3.位图索引的适用条件

位图索引适合只有几个固定值的列,如性别,婚姻状况,行政区等等,而身份证号这种类型不适合位图索引。

        此外,位图索引适合静态数据,而不适合索引频繁更新的列。举个例子,有这样一个字段busy,记录各个机器的繁忙与否,当机器忙碌时,busy为1,当机器不忙碌时,busy为0。

        这时候有人会说插入数据时可以使用位图索引,因为busy只有2个值。好,我们使用位图索引索引busy字段!假设用户a使用update更新某个机器的busy值,比如update table set table.busy=1 where rowid=100;,但还没有commit,而用户b也使用update更新令一个机器的busy值,update table set table.busy=1 where rowid=12;这时用户b怎么也更新不了,需要等待用户a commit

        原因:用户a更新了某个机器的busy值为1,会导致所有busy为1的机器的位图发生变化,因此数据库会将busy=1的所有行锁定,只有commit之后才会解锁