美文网首页
mysql索引的最左前缀原则

mysql索引的最左前缀原则

作者: 大龄程序员在帝都 | 来源:发表于2016-07-29 22:11 被阅读1781次

联合索引有一个最左前缀原则,所以建立联合索引的时候,这个联合索引的字段顺序非常重要
下面写了例子说明这个:

CREATE TABLE `test_myisam` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `conference_id` varchar(200) NOT NULL,
  `account` varchar(100) DEFAULT NULL,
  `status` int(2) DEFAULT NULL COMMENT '0:invite,  1:cancel_invite,  2:decline,  3:connect',
  `duration` bigint(20) unsigned DEFAULT NULL,
  `create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=myisam AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

以上表结构,我想通过三列进行查询 account ,status,create_time进行查询统计。
如何建立索引?
因为我们有可能按照acccount单独统计,或者按照account status,或者是account,status,create_time进行统计,如何建立索引???

下面是建立索引前后的对比600万数据
如何生成:执行如下脚本,account和日期不同还有status不同,分别生成一百万。



 CREATE  PROCEDURE `add_data_myisam_cp_27`()
    begin
    declare v_rows int(10) default 1000000;
    declare v_count int(10) default 0;
    id_loop:LOOP
    insert into test_myisam values(null,round(rand()*1000000000),'cloudp',round(rand()*3),round(rand()*100000),'2016-07-27 00:00:22');
    set v_count= v_count + 1;
    if v_count>v_rows then
    leave id_loop;
    end if;
    end loop id_loop;
    end;

测试结果利用建立的索引性能提高了三倍:

MariaDB [prf]> select count(1) from test_myisam where account='cloudp' and status =3 and date(create_time)='2016-07-27';
+----------+
| count(1) |
+----------+
|   167400 |
+----------+
1 row in set (1.28 sec)

MariaDB [prf]> create index as_index on test_myisam(account,status,create_time);
Query OK, 6000006 rows affected (31.60 sec)
Records: 6000006  Duplicates: 0  Warnings: 0

MariaDB [prf]> select count(1) from test_myisam where account='cloudp' and status =3 and date(create_time)='2016-07-27';
+----------+
| count(1) |
+----------+
|   167400 |
+----------+
1 row in set (0.42 sec)

MariaDB [prf]> explain select count(1) from test_myisam where account='cloudp' and status =3 and date(create_time)='2016-07-27';
+------+-------------+-------------+------+---------------+----------+---------+-------------+--------+--------------------------+
| id   | select_type | table       | type | possible_keys | key      | key_len | ref         | rows   | Extra                    |
+------+-------------+-------------+------+---------------+----------+---------+-------------+--------+--------------------------+
|    1 | SIMPLE      | test_myisam | ref  | as_index      | as_index | 308     | const,const | 520216 | Using where; Using index |
+------+-------------+-------------+------+---------------+----------+---------+-------------+--------+--------------------------+
1 row in set (0.00 sec)

从1.28秒下降到0.42秒
但是这个date(create_time)会对每一列都会转换后对比,这里会比较消耗性能;
如何利用上索引??
修改为:


MariaDB [prf]> explain select count(1) from test_myisam where account='cloudp' and status =3 and date(create_time)='2016-07-27';
+------+-------------+-------------+------+---------------+----------+---------+-------------+--------+--------------------------+
| id   | select_type | table       | type | possible_keys | key      | key_len | ref         | rows   | Extra                    |
+------+-------------+-------------+------+---------------+----------+---------+-------------+--------+--------------------------+
|    1 | SIMPLE      | test_myisam | ref  | as_index      | as_index | 308     | const,const | 520216 | Using where; Using index |
+------+-------------+-------------+------+---------------+----------+---------+-------------+--------+--------------------------+
1 row in set (0.00 sec)

MariaDB [prf]> select count(1) from test_myisam where account='cloudp' and status =3 and create_time  between '2016-07-27' and '2016-07-28';
+----------+
| count(1) |
+----------+
|   167400 |
+----------+
1 row in set (0.15 sec)

MariaDB [prf]> explain select count(1) from test_myisam where account='cloudp' and status =3 and create_time  between '2016-07-27' and '2016-07-28';
+------+-------------+-------------+-------+---------------+----------+---------+------+--------+--------------------------+
| id   | select_type | table       | type  | possible_keys | key      | key_len | ref  | rows   | Extra                    |
+------+-------------+-------------+-------+---------------+----------+---------+------+--------+--------------------------+
|    1 | SIMPLE      | test_myisam | range | as_index      | as_index | 312     | NULL | 174152 | Using where; Using index |
+------+-------------+-------------+-------+---------------+----------+---------+------+--------+--------------------------+
1 row in set (0.00 sec)

如上效率又提高了三倍,是因为扫描的数据行数减少了,最后一个create_time如果不用索引需要扫描52016行,如果使用了索引扫描174152行,命中的行数为:167400行,命中率非常高了。

这里有个疑问:
如果按照天进行统计,create_time作为联合索引的第一列,如何使用上这个索引呢????
至今没有想清楚,如果这一列是date类型可以直接用上索引,如果在oracle中可以date(create_time)建立函数式索引。但是mysql貌似不支持函数式索引。

一个解决方式是: create_time定义为 date类型,在每一列存入的时候,通过触发器自动把这一行修改为date类型。

如果有好的注意欢迎留言探讨,目前没有好的方式加上create_time,可以从业务上解决,就是每天的统计计算完成以后,直接把数据推到历史表中,统计结果单独存放。

相关文章

  • 索引

    这道题目考察的知识点是MySQL组合索引(复合索引)的最左优先原则。 最左前缀匹配原则 在mysql建立联合索引时...

  • Mysql索引失效

    mysql 索引失效的原因有哪些?Mysql索引失效的原因 1、最佳左前缀原则——如果索引了多列,要遵守最左前缀原...

  • 我去,为什么最左前缀原则失效了?

    问题 最近,在 mysql 测试最左前缀原则,发现了匪夷所思的事情。根据最左前缀原则,本来应该索引失效,走全表扫描...

  • MySQL建索引、查询优化

    索引 最左前缀匹配原则非常重要的原则,mysql会一直向右匹配直到遇到范围查询(>、<、between、like)...

  • Mysql语句优化的原则——让你写sql更加顺手

    使用索引的原则: 1.最左前缀匹配原则。 mysql会一直向右匹配直到遇到范围查询(>、<、between、lik...

  • mysql索引的最左前缀原则

    联合索引有一个最左前缀原则,所以建立联合索引的时候,这个联合索引的字段顺序非常重要下面写了例子说明这个: 以上表结...

  • MySQL索引相关原则

    索引创建原则 模糊查询请最好遵守最左前缀查询原则。 a.mysql会一直向右匹配直到遇到范围查询(>、<、betw...

  • 正常的MySQL索引优化和注意事项

    建索引的几大原则 1.最左前缀匹配原则 mysql会一直向右匹配直到遇到范围查询(>、<、between、like...

  • 11.MySQL组合索引的有序性

    组合索引的有序性和最左前缀原理【强制】理解组合索引最左前缀原则,避免重复建设索引,如果建立了(a,b,c),相当于...

  • MySQL优化

    MySQL语句优化原则 1. 小表驱动大表(针对查询),可以减少IO 2. 最左前缀法则(针对索引),索引了多列的...

网友评论

      本文标题:mysql索引的最左前缀原则

      本文链接:https://www.haomeiwen.com/subject/liwzjttx.html