mysql之字符串字段添加索引

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了mysql之字符串字段添加索引相关的知识,希望对你有一定的参考价值。

参考技术A

字符串创建索引方式:
1、直接创建完整索引,比较占用空间。
2、创建前缀索引,节省空间,但会增加查询扫描次数,并且不能使用覆盖索引。
3、倒序存储,在创建前缀索引,用于绕过字符串本身前缀的却分度不够的问题。
4、创建hash字段索引,查询性能稳定,有额外的存储和计算消耗。

倒序存储和hash字段索引都不支持范围查询。倒序存储的字段上创建的所有是按照倒序字符串的方式排序的。hash字段的方式也只能支持等值查询。

mysql> alter table SUser add index index1(email); :包含了每个记录的整个字符串

mysql> alter table SUser add index index2(email(6)); :-对于每个记录只取前6个字节

全字段索引操作流程
使用的是 index1(即 email 整个字符串的索引结构),执行顺序是这样的:
1、从 index1 索引树找到满足索引值是’ zhangssxyz@xxx.com ’的这条记录,取得 ID2 的值;
2、到主键上查到主键值是 ID2 的行,判断 email 的值是正确的,将这行记录加入结果集;
3、取 index1 索引树上刚刚查到的位置的下一条记录,发现已经不满足 email=\' zhangssxyz@xxx.com ’的条件了,循环结束。

前缀字段索引操作流程
如果使用的是 index2(即 email(6) 索引结构),执行顺序是这样的:
1、从 index2 索引树找到满足索引值是’zhangs’的记录,找到的第一个是 ID1;
2、到主键上查到主键值是 ID1 的行,判断出 email 的值不是’ zhangssxyz@xxx.com ’,这行记录丢弃;
3、取 index2 上刚刚查到的位置的下一条记录,发现仍然是’zhangs’,取出 ID2,再到 ID 索引上取整行然后判断,这次值对了,将这行记录加入结果集;
4、重复上一步,直到在 idxe2 上取到的值不是’zhangs’时,循环结束。

倒序查询和hash字段的区别
它们的区别,主要体现在以下三个方面:
1、从占用的额外空间来看,倒序存储方式在主键索引上,不会消耗额外的存储空间,而 hash 字段方法需要增加一个字段。当然,倒序存储方式使用 4 个字节的前缀长度应该是不够的,如果再长一点,这个消耗跟额外这个 hash 字段也差不多抵消了。
2、在 CPU 消耗方面,倒序方式每次写和读的时候,都需要额外调用一次 reverse 函数,而 hash 字段的方式需要额外调用一次 crc32() 函数。如果只从这两个函数的计算复杂度来看的话,reverse 函数额外消耗的 CPU 资源会更小些。
3、从查询效率上看,使用 hash 字段方式的查询性能相对更稳定一些。因为 crc32 算出来的值虽然有冲突的概率,但是概率非常小,可以认为每次查询的平均扫描行数接近 1。而倒序存储方式毕竟还是用的前缀索引的方式,也就是说还是会增加扫描行数。

MYSQL学习笔记之索引

MYSQL学习笔记之索引_索引

(一)什么是索引??

       索引(Index)是在数据库的字段上添加的,是为了提高查询的效率存在的一种机制。一张表的一个字段可以添加一个索引,当然,多个字段联合起来也可以添加索引。索引相当于是一本书的目录,主要是为缩小扫描范围而存在的一种机制。

(二)查询的分类

① 全表扫描(缺点:效率比较低,查询速度比较慢)

② 索引定位(优点:查询速度比较快,效率比较高)​

说明:对于通过索引的这一种查询方式,索引也是需要排序的,并且索引的排序和TreeSet数据结构相同。TreeSet(TreeMap)底层是一个自平衡二叉树!在mysql中索引是一个B-Tree的数据结构。

(三)索引的实现原理

假设存在一张用户表 t_user

    id(PK)                  name            每一行记录在硬盘上都有物理存储编号

------------------------------------------------------------------------------------

     100                      张三                        0x1111

     120                      李四                        0x2222

      99                       王五                        0x8888

      88                       赵六                        0x9999

     101                      小胡                        0x6666

      55                       小明                        0x5555

     130                      小红                        0x7777

说明:

I.在任何数据库当中主键上会自动添加索引对象,id字段上有自动索引。一个字段上如果有unique约束的话,也会自动创建索引对象。

II.在任何数据库当中,任何一张表的任何一条记录都在硬盘上存储都有一个硬盘上的物理编号。

III.在mysql中,所以是一个单独的对象,不同的存储引擎以不同的形式存在,在MYSQL存储引擎中,索引存储在一个.MYI文件中。在InnoDB存储引擎中,索引存储在一个逻辑名称叫做tablespace当中。在MEMORY存储引擎中索引被存储在内存当中。不管索引存储在哪里,索引在mysql中都是一个树的形式存在(自平衡二叉树:B-Tree)

构建与查找图示如下:

MYSQL学习笔记之索引_索引_02

(四)应用场景

① 数据量庞大

② 该字段经常出现在where的后面

③ 该字段进行很少的DML(insert 、delete、update)操作。

(频繁的DML操作会导致索引重新排序,降低效率)

注意:索引是不可以进行随意添加的,索引是需要维护的,索引太多反而会影响系统的性能,通过主键查询或通过unique约束的字段进行查询,效率很高。

(五)如何使用

I.索引的创建

mysql> create index emp_ename_index on emp(ename);
Query OK, 0 rows affected (0.04 sec)
Records: 0 Duplicates: 0 Warnings: 0

II.索引的删除

mysql> drop index emp_ename_index on emp;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0

III.查看索引方式

mysql> explain select * from emp where ename = KING;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

mysql> create index emp_ename_index on emp(ename);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> explain select * from emp where ename = KING;
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | emp | NULL | ref | emp_ename_index | emp_ename_index | 33 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+-----------------+-----------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

说明:MYSQL索引底层是B-Tree

IV.索引失效

情况一:explain select * from emp where ename like %T;

mysql> explain select * from emp where ename like %T;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 11.11 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

失效原因:模糊匹配当中条件使用了“%”开头(应该尽量避免)

情况二:explain select  * from emp where ename = KING or job=MANAGER;


mysql> explain select * from emp where ename = KING or job=MANAGER;
+----+-------------+-------+------------+------+-----------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+-----------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | emp_ename_index | NULL | NULL | NULL | 14 | 19.00 | Using where |
+----+-------------+-------+------------+------+-----------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

失效原因:在使用or时候,要求其两边的条件字段都需要有索引,才会通过索引进行检索,反之不可以。

#通过使用union来实现
mysql> explain select * from emp where ename = KING union select * from emp where job=MANAGER;
+----+--------------+------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+--------------+------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-----------------+
| 1 | PRIMARY | emp | NULL | ref | emp_ename_index | emp_ename_index | 33 | const | 1 | 100.00 | NULL |
| 2 | UNION | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 10.00 | Using where |
| NULL | UNION RESULT | <union1,2> | NULL | ALL | NULL | NULL | NULL | NULL | NULL | NULL | Using temporary |
+----+--------------+------------+------------+------+-----------------+-----------------+---------+-------+------+----------+-----------------+
3 rows in set, 1 warning (0.00 sec)

情况三:create index emp_job_sal_index on emp(job,sal);

#创建索引
mysql> create index emp_job_sal_index on emp(job,sal);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0

#查看索引次数
mysql> explain select * from emp where job=MANAGER;
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | emp | NULL | ref | emp_job_sal_index | emp_job_sal_index | 30 | const | 3 | 100.00 | NULL |
+----+-------------+-------+------------+------+-------------------+-------------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

#查看索引次数
mysql> explain select * from emp where sal = 800;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 10.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

失效原因:在复合索引(两个及以上字段联合起来添加索引)中。没有使用左侧的列查找,索引失效。

情况四:explain select * from emp where sal+1=800;

mysql> create index emp_sal_index on emp(sal);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0

mysql> explain select * from emp where sal=800;
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
| 1 | SIMPLE | emp | NULL | ref | emp_sal_index | emp_sal_index | 9 | const | 1 | 100.00 | NULL |
+----+-------------+-------+------------+------+---------------+---------------+---------+-------+------+----------+-------+
1 row in set, 1 warning (0.00 sec)

mysql> explain select * from emp where sal+1=800;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

失效原因:在where中索引参与了运算。

情况五:explain select * from emp where lower(ename)=smith;

mysql> explain select * from emp where lower(ename)=smith;
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
| 1 | SIMPLE | emp | NULL | ALL | NULL | NULL | NULL | NULL | 14 | 100.00 | Using where |
+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)

失效原因: 在where中索引使用了函数

V.索引分类

① 单一索引:一个字段上添加索引。

②复合索引: 两个及以上字段上添加索引。

③主键索引​:主键上添加索引。

④唯一性索引:具有unique约束的字段上添加索引。

以上是关于mysql之字符串字段添加索引的主要内容,如果未能解决你的问题,请参考以下文章

Mysql实战篇之怎么给字符串加索引--03

mysql笔记-字段上的函数操作会使索引失效

Mysql 架构和索引

MySQL字符串索引创建方案

mysql前缀索引的应用

MYSQL之索引配置方法分类