操作 | 时间复杂度 | 说明 |
---|---|---|
查询 | O(logN) | 二分法 |
插入 | O(N) | |
删除 | O(logN) | 标记删除(软删除) |
适用环境:插入较少的情况,不再变化的数据,比如去年的销售情况
操作 | 时间复杂度 | 说明 |
---|---|---|
查询 | O(1) | |
插入 | O(1) | |
删除 | O(1) |
以key-value存储,可以拉链来解决冲突
适用环境:范围查询较少
操作 | 时间复杂度 | 说明 |
---|---|---|
查询 | O(logN) | |
插入 | O(logN) | |
删除 | O(logN) |
适用环境:内存
lsm全称日志结构合并树,它并不是一种具体的数据结构,而是一种思想,多用于大数据中。
对比普通的索引,当写数据的时候可能需要从磁盘中读取数据,再修改,有一个随机访问磁盘的过程。lsm为了提供写效率,去除了随机访问磁盘的过程,那么它是怎么做的呢?
我们知道数据存在于内存和磁盘,内存作为缓存加快读写,lsm树也是如此。它由一个内存区域和一系列的磁盘上的文件,每一个文件都有一定的格式,并且数据在文件内部是有序的。写入数据的时候只写入内存,当内存到达阈值的时候就将内存中的数据构造为一个文件,然后刷下去,这样就有多了一个文件。
当读数据的时候就比较麻烦了,需要访问每一个文件以及内存,因为他们不是整体有序的,读的效率比较低。当然为了提高读的效率会有一些优化,比如文件的格式中有[keyStart,keyEnd],布隆过滤器等。
lsm树无法避免的一个操作就是compaction,为了提高写的效率,它会将多个文件合并为一个,当然这会消耗内存和cpu的资源,极端的情况会产生读毛刺。
lsm树在大数据领域应用十分广泛,比如在hbase中,influxdb也使用了更改后的lsm树
操作 | 时间复杂度 | 说明 |
---|---|---|
查询 | O(logmN) | |
插入 | O(logmN) | |
删除 | O(logmN) |
操作 | 时间复杂度 | 说明 |
---|---|---|
查询 | O(logmN) | |
插入 | O(logmN) | |
删除 | O(logmN) |
是否是唯一索引在查询,加锁,插入等情况的性能是不同的。
select _rowid from xxx;
force index(xxx)
强制使用某个索引
b+树索引通常在生成上的树高为2-4,那么逻辑IO只有2-4,假如机械硬盘每秒100次IO,那么一次查询最快只需要0.02-0.04秒,很快了。
辅助索引又称之为二级索引,也是采用b+树实现,当根据二级索引查询的时候,如果要查找的数据不是二级索引树上叶子节点上的数据(索引值本身,主键),那么会根据主键值进行回表:扫描主键索引树。
在组合索引中,可以使用前缀匹配:匹配前n个字符或者前m个字段,组合索引的排序方式是先排第一个字段,第一个字段相同再排其他字段。假如组合索引不是主键,在查询的时候也需要回表,但是在5.6之后引入了索引下推,如果要查询的值是主键或者是组合索引中的值,就可以不回表。
k=spance_id<<20+spance_id+offset
使用倒排索引来实现。
在一个辅助表中存储了单词与单词在一个或多个文档的映射,使用关联数组实现:
mysql> show index from test1;
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| test1 | 0 | PRIMARY | 1 | id | A | 10 | NULL | NULL | | BTREE | | |
| test1 | 1 | a | 1 | a | A | 10 | NULL | NULL | YES | BTREE | | |
+-------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec)
通过show index from xxx;
查看索引。
工作方式:
好处:
在根据索引查询时,会在引擎层判断是否可以使用where进行过滤,而不是将数据返回server层在过滤。用在联合索引上。
MySQL支持降序索引,在创建索引的时候添加asc 或者 desc
例子:
CREATE TABLE t (
c1 INT, c2 INT,
INDEX idx1 (c1 ASC, c2 ASC),
INDEX idx2 (c1 ASC, c2 DESC),
INDEX idx3 (c1 DESC, c2 ASC),
INDEX idx4 (c1 DESC, c2 DESC)
);
ORDER BY c1 ASC, c2 ASC -- optimizer can use idx1
ORDER BY c1 DESC, c2 DESC -- optimizer can use idx4
ORDER BY c1 ASC, c2 DESC -- optimizer can use idx2
ORDER BY c1 DESC, c2 ASC -- optimizer can use idx3
InnodB会自动的扩展二级索引:添加主键到二级索引中。
比如:
CREATE TABLE t1 (
i1 INT NOT NULL DEFAULT 0,
i2 INT NOT NULL DEFAULT 0,
d DATE DEFAULT NULL,
PRIMARY KEY (i1, i2),
INDEX k_d (d)
) ENGINE = InnoDB;
实际上:二级索引是:(d,i1,i2)
比如:
mysql> EXPLAIN SELECT COUNT(*) FROM t3 WHERE i1 = 3 AND d = '2000-01-01';
+----+-------------+-------+------------+------+---------------+------+---------+-------------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+-------------+------+----------+-------------+
| 1 | SIMPLE | t3 | NULL | ref | PRIMARY,k_d | k_d | 8 | const,const | 1 | 100.00 | Using index |
+----+-------------+-------+------------+------+---------------+------+---------+-------------+------+----------+-------------+
可以看到,key_len 是8字节(d是4字节),而ref也是两个const,rows是1(在我的数据库中满足d = '2000-01-01’的rows应该是5).
select "10">9
,返回1表示转换为数字mysql> select d.* from tradelog l, trade_detail d where d.tradeid=l.tradeid and l.id=2;
假如l表的编码是utf-8,而d表示utf8mb64,这条语句首先会使用l表的索引查出一条语句,然后去d表中查询,但是由于编码不同,涉及到了编码自动转换的问题,也就是需要一个转换的函数,由于utf8mb64是utf8的超集,因此d表中的索引需要一个函数转换为utf8mb64,也就违反了第一条规则。
但是如果使用的字符集相反,那么就只使用一次编码转换,依旧可以使用第二个索引
主键最好使用递增的值,较小的值,比如自增主键。
如果使用无序的值,插入会使得数据页经常分裂,导致数据页镂空,不能有效的利用IO。在这个时候可以重建表。
建立联合索引的时候:考虑索引的复用能力,来确定是否建立索引,索引字段的顺序
查询的时候也需要考虑能否利用前缀匹配,覆盖索引
查询时:
插入时:
加锁时:
alter table t add index index1(email(6));
,前缀索引会带来多次搜索的代价,因此可以使用count(distinct left(email,5)) as l5,count(distinct left(email,6)) as l6,count(distinct left(email,7)) as l7
来判断最好的长度,只要超过95%就行reverse()
函数crc32()
产生的校验码,同时给这个字段加上索引;但是校验码可能会冲突,因此还需在查询的时候同时比较校验码与源字段更多请看下一篇MySQL索引合并