ITPub博客

首页 > 数据库 > MySQL > MySQL Count(*)提速30倍

MySQL Count(*)提速30倍

原创 MySQL 作者:壹頁書 时间:2014-04-22 19:40:36 0 删除 编辑
MySQL InnoDB是索引组织表,如果根据主键大范围查询,效率非常低下。
因为主键索引中还包含数据,需要扫描大量的块。

这种场景,如果有一个二级索引,则可以极大的提升查询速度。

初始化实验数据(100W记录)


  1. --创建实验表
  2. create table t(
  3.     id int primary key,
  4.     num int,
  5.     content varchar(1000)
  6. )engine=innodb;

  7. --创建可以产生随机字符串的函数
  8. DROP FUNCTION IF EXISTS rand_string;
  9. delimiter //
  10. CREATE FUNCTION rand_string(l_num int UNSIGNED,l_type tinyint UNSIGNED)
  11. RETURNS varchar(2000)
  12. BEGIN
  13.  -- Function : rand_string
  14.  -- Author : dbachina#dbachina.com
  15.  -- Date : 2010/5/30
  16.  -- l_num : The length of random string
  17.  -- l_type: The string type
  18.  -- 1.0-9
  19.  -- 2.a-z
  20.  -- 3.A-Z
  21.  -- 4.a-zA-Z
  22.  -- 5.0-9a-zA-Z
  23.  -- :
  24.   -- mysql> select rand_string(12,5) random_string;
  25.   -- +---------------+
  26.   -- | random_string |
  27.   -- +---------------+
  28.   -- | 3KzGJCUJUplw  |
  29.   -- +---------------+
  30.   -- 1 row in set (0.00 sec)
  31.  DECLARE i int UNSIGNED DEFAULT 0;
  32.  DECLARE v_chars varchar(64) DEFAULT '0123456789';
  33.   DECLARE result varchar (2000) DEFAULT '';
  34.  
  35.   IF l_type = 1 THEN
  36.     SET v_chars = '0123456789';
  37.   ELSEIF l_type = 2 THEN
  38.     SET v_chars = 'abcdefghijklmnopqrstuvwxyz';
  39.   ELSEIF l_type = 3 THEN
  40.     SET v_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
  41.   ELSEIF l_type = 4 THEN
  42.     SET v_chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  43.   ELSEIF l_type = 5 THEN
  44.     SET v_chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
  45.   ELSE
  46.     SET v_chars = '0123456789';
  47.   END IF;
  48.  
  49.   WHILE i < l_num DO
  50.       SET result = concat( result,substr(v_chars,ceil(rand()*(length(v_chars)-1)),1) );
  51.     SET i = i + 1;
  52.   END WHILE;
  53.   RETURN result;
  54. END;
  55. //
  56. delimiter ;

  57. --插入100W条实验数据
  58. DROP PROCEDURE IF EXISTS insertTableT;
  59. delimiter //
  60. create procedure insertTableT()
  61. begin
  62.     declare i int;
  63.     set i=0;
  64.     while i<1000000 do
  65.         insert into t values(i,i,rand_string(1000,5));
  66.         set i=i+1;
  67.     end while;
  68. end;
  69. //
  70. delimiter ;

使用主键索引的count(*)查询

  1. mysql> explain select count(*) from t;
  2. +----+-------------+-------+-------+---------------+---------+---------+------+--------+-------------+
  3. | id | select_type | table | type  | possible_keys | key     | key_len | ref  | rows   | Extra       |
  4. +----+-------------+-------+-------+---------------+---------+---------+------+--------+-------------+
  5. | 1  | SIMPLE      | t     | index | NULL          | PRIMARY | 4       | NULL | 931113 | Using index |
  6. +----+-------------+-------+-------+---------------+---------+---------+------+--------+-------------+
  7. 1 row in set (0.00 sec)

  8. mysql> select count(*) from t;
  9. +----------+
  10. | count(*) |
  11. +----------+
  12. | 1000000  |
  13. +----------+
  14. 1 row in set (6.85 sec)

使用二级索引的count(*)查询

  1. mysql> create index t_num on t(num);
  2. Query OK, 0 rows affected (9.55 sec)
  3. Records: 0 Duplicates: 0 Warnings: 0

  4. mysql> explain select count(*) from t;
  5. +----+-------------+-------+-------+---------------+-------+---------+------+--------+-------------+
  6. | id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows   | Extra       |
  7. +----+-------------+-------+-------+---------------+-------+---------+------+--------+-------------+
  8. | 1  | SIMPLE      | t     | index | NULL          | t_num | 5       | NULL | 931113 | Using index |
  9. +----+-------------+-------+-------+---------------+-------+---------+------+--------+-------------+
  10. 1 row in set (0.00 sec)

  11. mysql> select count(*) from t;
  12. +----------+
  13. | count(*) |
  14. +----------+
  15. | 1000000  |
  16. +----------+
  17. 1 row in set (0.18 sec)
使用二级索引相比主键索引有近30倍的提升。

但是奇怪的是,按照Oracle对于索引的描述,不全为null的内容可以被索引。
很明显,t表的num字段可以为空。
插入一个空值之后,居然还可以使用索引??非常奇怪
  1. mysql> insert into t(id,num,content) values(1000001,null,'1');
  2. Query OK, 1 row affected (0.02 sec)

  3. mysql> commit;
  4. Query OK, 0 rows affected (0.04 sec)
包含null值,依然使用索引的count(*)

  1. mysql> explain select count(*) from t;
  2. +----+-------------+-------+-------+---------------+-------+---------+------+--------+-------------+
  3. | id | select_type | table | type  | possible_keys | key   | key_len | ref  | rows   | Extra       |
  4. +----+-------------+-------+-------+---------------+-------+---------+------+--------+-------------+
  5. | 1  | SIMPLE      | t     | index | NULL          | t_num | 5       | NULL | 931114 | Using index |
  6. +----+-------------+-------+-------+---------------+-------+---------+------+--------+-------------+
  7. 1 row in set (0.00 sec)

  8. mysql> select count(*) from t;
  9. +----------+
  10. | count(*) |
  11. +----------+
  12. | 1000001  |
  13. +----------+
  14. 1 row in set (0.18 sec)
  对空值的查询居然还能使用索引?

  1. mysql> explain select * from t where num is null;
  2. +----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------+
  3. | id | select_type | table | type | possible_keys | key   | key_len | ref   | rows | Extra                 |
  4. +----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------+
  5. | 1  | SIMPLE      | t     | ref  | t_num         | t_num | 5       | const | 1    | Using index condition |
  6. +----+-------------+-------+------+---------------+-------+---------+-------+------+-----------------------+
  7. 1 row in set (0.00 sec)

  8. mysql> select * from t where num is null;
  9. +---------+------+---------+
  10. | id      | num  | content |
  11. +---------+------+---------+
  12. | 1000001 | NULL | 1       |
  13. +---------+------+---------+
  14. 1 row in set (0.00 sec)
不走索引着急,不明白为什么走索引也着急。
 

来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/29254281/viewspace-1147227/ ,如需转载,请注明出处,否则将追究法律责任。

下一篇: Redis
请登录后发表评论 登录
全部评论

注册时间:2013-10-19

  • 博文量
    620
  • 访问量
    6339922