为了账号安全,请及时绑定邮箱和手机立即绑定

通过实例来理解MySQL索引

标签:
MySQL


索引的使用

首先建立库之后,并创建表,表结构如下:

mysql> createdatabase test1;

Query OK, 0 rowsaffected (0.01 sec)

mysql> use test1;

Database changed

mysql> createtable yw (

    -> id int unsigned not nullauto_increment,

    -> c1 int not null default '0',

    -> c2 int not null default '0',

    -> c3 int not null default '0',

    -> c4 int not null default '0',

    -> c5 timestamp not null,

    -> c6 varchar(200) not null default '',

    -> primary key(id)

    -> );

Query OK, 0 rowsaffected (0.01 sec)

 

导入sql文件

内容如下

[root@mysql_node1test]# cat suoyin_test.sql

 

drop table yw;                      #已将刚才创建的库删除了,然后又重新创建了一个库

create table yw (

id int unsigned notnull primary key auto_increment,

c1 int not nulldefault '0',

c2 int not nulldefault '0',

c3 int not nulldefault '0',

c4 int not nulldefault '0',

c5 timestamp notnull,

c6 varchar(200) notnull default ''

);

 

delimiter $$

drop procedure ifexists `insert_yw` $$

create procedure`insert_yw`(in row_num int )

begin

 declare i int default 0;

 while i < row_num do

    insert into yw(c1, c2, c3,c4, c5,c6) values(floor(rand()*row_num),floor(rand()*row_num),floor(rand()*row_num),floor(rand()*row_num),now(),repeat('wubx', floor(rand()*20)));

    set i = i+1;

 END while;

end$$

delimiter ;

 

#插入300W条数据

callinsert_yw(3000000);

 

 

delimiter $$

drop procedure ifexists `update_yw` $$

create procedure`update_yw`(in row_num int )

begin

 declare i int default 0;

 while i < row_num do

     update yw set c3= floor(rand()*row_num) whereid=i;

    set i = i+1;

 END while;

end$$

delimiter ;

更改参数

mysql> set globalinnodb_flush_log_at_trx_commit=2

导入数据表

mysql> source/root/test/suoyin.sql

Query OK, 0 rowsaffected (0.11 sec)

 

Query OK, 0 rowsaffected (0.01 sec)

 

Query OK, 0 rowsaffected (0.00 sec)

 

Query OK, 0 rowsaffected (0.00 sec)

 

Query OK, 1 row affected(4 min 20.75 sec)

 

Query OK, 0 rowsaffected (0.00 sec)

 

Query OK, 0 rowsaffected (0.00 sec)

我们会发现导入很慢,当然300W条数据也不小,所以我们的问题来了:

 

为什么这个查询这么慢?

mysql> select *from yw a, (select c2 from yw where id=10) b where a.c2 =b.c2;

+---------+---------+--------+---------+---------+---------------------+------------------------------------------------------------------+--------+

| id      | c1     | c2     | c3      | c4     | c5                  | c6                                                               | c2     |

+---------+---------+--------+---------+---------+---------------------+------------------------------------------------------------------+--------+

|      10 | 2833881 | 185188 | 1424297 |  565924 | 2014-09-24 14:30:31 |wubxwubxwubxwubxwubxwubxwubxwubxwubxwubx                         | 185188 |

| 1530223 | 1345871 |185188 | 2888330 | 1886085 | 2014-09-24 14:32:44 | wubxwubxwubxwubxwubx                                             |185188 |

| 1623964 | 1289414 |185188 |   57699 | 2732932 | 2014-09-2414:32:52 | wubxwubxwubxwubxwubxwubxwubxwubxwubx                             | 185188 |

| 2825263 |  729557 | 185188 | 1737273 | 2130798 |2014-09-24 14:34:37 | wubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubx| 185188 |

+---------+---------+--------+---------+---------+---------------------+------------------------------------------------------------------+--------+

4 rows in set (7.28 sec)

经过最后查看,显示的是7.28秒执行完成,一个很简单的查询但是执行完后会很慢,

那么这里我们看到一个2825263, 那么我们将sql改为一个简单的sql并查看

 

这是一个非常简单的sql,如果在有索引的300w的数据,应该是非常快的,但实际上的表结构跑这样的sql还是很慢的,如下所示,总共用了7.96秒,如下所示:

mysql>  select * from yw where c1 = 2825263 ;

+---------+---------+---------+---------+---------+---------------------+------------------------------------------------------+

| id      | c1     | c2      | c3      | c4     | c5                  | c6                                                  |

+---------+---------+---------+---------+---------+---------------------+------------------------------------------------------+

| 1421241 | 2825263 |2015825 | 1603339 | 1969218 | 2014-09-24 14:32:35 |wubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubx |

+---------+---------+---------+---------+---------+---------------------+------------------------------------------------------+

1 row in set (7.96 sec)

之所以慢,是因为在全表扫描而造成的

这种情况下可以对其进行添加索引进行优化

 

再次追加300万条数据

使用call insert_表名 进行添加

mysql> call insert_yw(3000000);

Query OK, 1 rowaffected (4 min 21.74 sec)

 

大概在7分钟将索引添加将300万条数据加载完毕

PS:在生产环境中都要模拟百万条的数据去进行测试

 

创建完后查看索引大小,大概476M左右

[root@mysql_node1test1]# ll -th

总用量 477M

-rw-rw----. 1 mysqlmysql 476M 9月  24 14:49 yw.ibd

-rw-rw----. 1 mysqlmysql 8.6K 9月  24 14:30 yw.frm

-rw-rw----. 1 mysqlmysql   61 9月  24 14:00 db.opt

 

mysql> desc select* from yw a, (select c2 from yw where id=10) b where a.c2 =b.c2;

+----+-------------+------------+--------+---------------+---------+---------+------+---------+-------------+

| id | select_type |table      | type   | possible_keys | key     | key_len | ref  | rows   | Extra       |

+----+-------------+------------+--------+---------------+---------+---------+------+---------+-------------+

|  1 | PRIMARY     | <derived2> | system | NULL          | NULL    | NULL   | NULL |       1 |             |

|  1 | PRIMARY     | a          | ALL    | NULL          | NULL    | NULL   | NULL | 5936589 | Using where |

|  2 | DERIVED     | yw         | const  | PRIMARY      | PRIMARY | 4       |     |       1 |             |

+----+-------------+------------+--------+---------------+---------+---------+------+---------+-------------+

3 rows in set (0.00sec)

 

 

索引的使用

索引的简介

索引实际上是Btree结构

有些生产环境上尤其是在主从环境下用不到索引的,从而使得主从延迟,当发现从库延迟,要先去定位是否是从库上有sql写入的时间是否没有用到索引,如果是的话则加索引即可

这类情况在排查主从结构的时候特别多

而delete也是支持索引的,如果不进行索引,那么也会进行全表扫描

比如在某场景下我们要批量删除大量数据,通常建议使用工具或存储过程去分段(批量)删除数据,比如:

     deletefrom tb where addtime&get;xxxx and addtime<xxxx;

使用这样的语句去按段删除

 

通过索引可以让update selecet delete 都可以实现到加速,但添加索引的话对写入影响较重

主建是不能去执行update的,生产中是不应该对update做索引的 因为update会将表重新组织一遍并进行btree重排序,所以会非常慢

 

创建索引,并将其进行对比

将之前创建的表改名并添加新所索引

 

mysql> renametable yw to yw_1;

ERROR 2006 (HY000):MySQL server has gone away

No connection. Tryingto reconnect...

Connection id:    12

Current database:test1

 

Query OK, 0 rowsaffected (0.11 sec)

 

mysql> showtables;

+-----------------+

| Tables_in_test1 |

+-----------------+

| yw_1            |

+-----------------+

1 row in set (0.00sec)

 

新建表

create table yw (

    id int unsigned not null auto_increment,

     c1 int not null default '0',

     c2 int not null default '0',

     c3 int not null default '0',

     c4 int not null default '0',

     c5 timestamp not null,

     c6 varchar(200) not null default '',

     primary key(`id`),

     KEY `idx_c2`(`c2`),

     key `idx_c3`(`c3`)

     );

Query OK, 0 rowsaffected (0.03 sec)

查看表结构

mysql> desc yw;

+-------+------------------+------+-----+-------------------+-----------------------------+

| Field | Type             | Null | Key | Default           | Extra                       |

+-------+------------------+------+-----+-------------------+-----------------------------+

| id    | int(10) unsigned | NO   | PRI | NULL              | auto_increment              |

| c1    | int(11)          | NO  |     | 0                 |                             |

| c2    | int(11)          | NO  | MUL | 0                 |                             |

| c3    | int(11)          | NO  | MUL | 0                 |                             |

| c4    | int(11)          | NO  |     | 0                 |                             |

| c5    | timestamp        | NO  |     | CURRENT_TIMESTAMP | onupdate CURRENT_TIMESTAMP |

| c6    | varchar(200)     | NO  |     |                   |                             |

+-------+------------------+------+-----+-------------------+-----------------------------+

7 rows in set (0.07sec)

 

[root@mysql_node1test]# cat 2.sql

delimiter $$

drop procedure ifexists `update_yw` $$

create procedure`update_yw`(in row_num int )

begin

declare i int  default 0;

while i < row_numdo

update yw set c3=floor(rand()*row_num) where id=i;

set i = i+1;

END while;

end$$

delimiter ;

导入

mysql> source/root/test/2.sql

Query OK, 0 rowsaffected (0.00 sec)

Query OK, 0 rowsaffected (0.00 sec)

 

再次插入300W条记录,查看用时时间

mysql> callinsert_yw(3000000);

Query OK, 1 rowaffected (8 min 11.57 sec)

 

将之前备份的表还原并再次执行,这里插入一百万条数据

mysql> renametable yw to yw_idx;

Query OK, 0 rowsaffected (0.06 sec)

 

mysql> renametable yw_1 to yw;

Query OK, 0 rowsaffected (0.01 sec)

 

mysql> showtables;

+-----------------+

| Tables_in_test1 |

+-----------------+

| yw              |

| yw_idx          |

+-----------------+

2 rows in set (0.00sec)

 

这样一个是带索引,一个是不带索引的

再次调用包含索引的结构

mysql>  call update_yw(3000000);

Query OK, 1 rowaffected (4 min 32.31 sec)

 

与之对比如下:

表名

是否所用索引

执行过程所耗时间

yw

11.57 sec

yw_idx

32.31 sec

两者间速度相差3倍左右

 

如果存在c3的索引的话,那么执行以下sql语句:

select c3 from yw where id=1;

发现同样是很慢的,因为在发生更新第三列的时候同时需要做索引的维护

索引同样是Btree结构,如果发生任何变更的时候,会将Btree更新,重新排序,这样就会重新开销所以会慢

 

 

MySQL支持什么样的索引?

一般来讲都5类

普通索引,唯一索引,主建,组合索引,全文索引(mysql5.6的特性)

全文搜索第三方工具:sphinx

 

创建索引:

create index idx_xxx ontb(xxx);

更新索引:

alter table tb add indexidx_xxx(xxx);

删除索引:

DROP [ONLINE|OFFLINE]INDEX index_name ON tbl_name

 

普通索引一般包含前缀索引,如果前端部分很长可以建立前缀索引(前字符区分开来,减少一下索引的长度,让扫起来更省点IO),如下所示:

alter table yw add indxidx_c6_6(c6(6));

 

普通索引是的列是可以NULL的

 

唯一索引:

在设计中属于一种约束,在使用中,设置字段唯一的,或者是联合索引

例:

select * from table_nameidx_xxx=xxx;

如果在普通索引中,在记录中探测到下下条再判断是否是需要的记录,如果是则返回,所以普通索引是要往下多度几次,这是普通索引的开销

但唯一索引,只做等于匹配,不会再往下进行,其好处是比较节省IO,

唯一索引列可以允许有NULL,但只能有一个

 

主建

Innodb里聚集class index key以为所有的数据以主建排序存储  

主建是不允许有null列的

 

组合索引(联合索引):

    也被称为

 select * from yw where c4=XXXX order by c3;

使用explain查看执行性能

 

mysql> explainselect * from yw_idx where c3=251609 order by c4;

+----+-------------+--------+------+---------------+--------+---------+-------+------+-----------------------------+

| id | select_type |table  | type | possible_keys | key    | key_len | ref   | rows |Extra                       |

+----+-------------+--------+------+---------------+--------+---------+-------+------+-----------------------------+

|  1 | SIMPLE      | yw_idx | ref  | idx_c3        | idx_c3 | 4       | const |    1 | Using where; Using filesort |

+----+-------------+--------+------+---------------+--------+---------+-------+------+-----------------------------+

1 row in set (0.03sec)

实际执行sql还是很慢,key_len为4,但是还会很慢,这种sql是忽悠人的,但是实际上possible_keys里面是没有东西的,这属于一种欺骗性的所以需要注意

 

使用where条件判断

如果是前缀索引如果用到了c3 是否还可以继续调用c4字段

select * from yw where c3=xxx or c4=xxxx; 

select * from yw where c3=xxx union all select * from yw where c4=xxxx;

可以看到是不能调用的,因为在这个条件里面,c3是可以用到的,而c4是不行的,因为c4是全表扫描的,如有一个地方需要全表扫描的话,那么不管如何都是需要全表扫描,这也是mysql的一个特性 

如果是独立的字段,将c3和c4独立出来,则可以使用索引

 

以下是没有意义的索引

select count(*) from yw group by c3, c4;

使用两个字段独立索引都被进行调用

 

使用多索引合并

在5.5版本以上可以使用union 进行多索引合并

mysql> select *from yw where c3=xxx union all select * from yw where c4=xxxx;

这样c3 c4都有索引 ,这样的话sql是非常快的

 

如果使用以下sql语句:

mysql> selectcount(*) from yw group by c3, c4;

2999999 rows in set(57.26 sec)

虽然会用到索引,但是还是会全表扫描,因为扫描的IO过大,用到索引意义也不是很大

如果看到结果集超过一万行,都可以认为这个sql是可以杀掉了

只要结果集超过1万行(OLTP)环境,都可以认为这个SQL是有问题的

所以,最好控制结果集查询大小超过500,这样就可以避免过大全表扫描,避免IO过高

 

使用limit

如果我们为其后面加入limit 10 来查看效果

mysql> explainselect count(*)  from yw_idx group byc3,c4 order by id limit 10;

+----+-------------+--------+------+---------------+------+---------+------+---------+---------------------------------+

| id | select_type |table  | type | possible_keys | key  | key_len | ref  | rows   | Extra                          |

+----+-------------+--------+------+---------------+------+---------+------+---------+---------------------------------+

|  1 | SIMPLE      | yw_idx | ALL  | NULL          | NULL | NULL    | NULL | 3016886 | Using temporary; Usingfilesort |

+----+-------------+--------+------+---------------+------+---------+------+---------+---------------------------------+

1 row in set (0.00sec)

速度并没有提升,这种sql在生产环境也是较多

 

覆盖索引是能够查到数据

在生产中,一个表的查询是能够数过来的,但是非常小的业务系统非常复杂

例:

Create fulltext indexidx_xxx on TbName(xxxx);

select * from tbwhere match(xxxx) against(‘wubx’);

 

使用索引中注意的事项

首先创建表结构:

mysql> createtable tb_1 (

    ->     id int unsigned not null auto_increment,

    ->     c1 varchar(200) default null ,

    ->     c2 int not null,

    ->     primary key (id)

    ->     );

Query OK, 0 rowsaffected (0.06 sec)

插入数据

mysql> insert intotb_1(c1, c2) values(NULL,1),(1,2),(NULL,3);

Query OK, 3 rowsaffected (0.01 sec)

Records: 3  Duplicates: 0 Warnings: 0

查看每列的数据量

mysql> selectcount(c1) ,count(*) ,count(1), count(c2),count(id) from tb_1;

+-----------+----------+----------+-----------+-----------+

| count(c1) |count(*) | count(1) | count(c2) | count(id) |

+-----------+----------+----------+-----------+-----------+

|         1 |        3 |        3 |         3 |         3 |

+-----------+----------+----------+-----------+-----------+

1 row in set (0.00sec)

 

mysql> select *from tb_1;

+----+------+----+

| id | c1   | c2 |

+----+------+----+

|  1 | NULL | 1 |

|  2 | 1   |  2 |

|  3 | NULL | 3 |

+----+------+----+

3 rows in set (0.00sec)

这里面观察出,null是不被统计的,而且null在设计字段里如果需要的,需要多一个字节去标示,所以需要多占用一个标示位

所以我们需要注意的是:

1.索引不会包含有NULL值的列

2.普通索引列可以有NULL

 

索引的选择区分度最大:

比如索引的字段,比如性别男&女 这个值如果在在几千万的数据那么很小,但是在表里面有列是最大的,则是用户的ID号:user_id,每个用户的ID是唯一的,那么这个列是可以作为索引的,因为是区分度也就是最高的,另外需要使用短索引,如果用户名里定义的是varchar(32)实际上我们可以用15个就可以标记出来那么我们可以:

create index idx_username ontable_name (username(15));

 

 

查询中使用like 

例:

like "%aaa%"      #这种是不能够用到索引的

idx_c6(c6)  where c6 like "av%";  

而 like av% 是能够用到索引

idx_c6(c6)

 where c6 like "av%"

这样也是可以用到索引的,like语句如果前后百分号是不能用索引的,如果是以字符开头并以百分号结尾的是可以用到索引的

#如果区分度已经有user_id 这种特别大的列,那么就没有必要做其他操作,所以不建议将区分度大的索引与其他索引放在一起,如果放在一起是为了实现索引覆盖或查询这种特殊场景,是比较合适的,因为是无法回表

 

不在列上进行运算

排完序需要取最终的数据,比如oder by 或group by 或select * 之类的sql,索引中没有包含特殊的数据都是需要回表的

尤其是select * 的语句如果没有建立全表索引都是要回表的

如下所示:

select * from users where YEAR(adddate)< 2007; 

adddate timestamp

 

这种sql太多是用不到索引的,如果改为基于事件查询则可以:

(因为2007也是通过参数传递进来的)

select * from useradddate <'2007-01-01 00:00:00';

select *   from  tbwhere addtime > '2000-01-01 00:00:00' < '2014-XX-XX XX:XX:XX.';

将其换为小一点的时间这样意义大一些

 

差劲的sql案例:

包含不等于,比如id = 1; 

select * from ywwhere id!=1;

表示如果不等于1的id 其他全部打印出来。

mysql>explain  select * from yw_idx whereid!=1;

+----+-------------+--------+-------+---------------+---------+---------+------+---------+-------------+

| id | select_type |table  | type  | possible_keys | key     | key_len | ref  | rows    | Extra       |

+----+-------------+--------+-------+---------------+---------+---------+------+---------+-------------+

|  1 | SIMPLE      | yw_idx | range | PRIMARY       | PRIMARY | 4       | NULL | 1508444| Using where |

+----+-------------+--------+-------+---------------+---------+---------+------+---------+-------------+

1 row in set (0.08sec)

这样的话相当于一次全表扫描

从扫描的行数来看,优化器explain中有rows字段

从row列表中,可看到接近全表的操作

 

这里还有一个情况,我们使用limit并查看效果

mysql> select *from yw where id!=1 limit 1;

+----+---------+--------+---------+--------+---------------------+--------------+

| id | c1      | c2    | c3      | c4     | c5                  | c6           |

+----+---------+--------+---------+--------+---------------------+--------------+

|  2 | 2333997 | 269341 | 2459005 | 915557 |2014-09-24 15:38:29 | wubxwubxwubx |

+----+---------+--------+---------+--------+---------------------+--------------+

1 row in set (0.00sec)

 

select * from ywwhere id!=1;

select * from ywwhere id!=1 limit 1;

以上两者可以对比

 

看起来没有变化还是这么多行,但是在limit执行的时候会有流式化的输出,每当读取到一行的时候会放入到buffer池中,存到一定数量后会对其进行一次排序,如当已满足条件了,则不会再进行匹配

但是如果limit之后,速度会快很多,虽然看到此情况,可能会用到索引了,这也是用索引的一种场景

 

使用not in

not in的主要作用是在执行sql查询语句的时候不在哪一个数据范围的的记录

mysql> select *from yw_idx where c2 not in(4262384,3605632);

 

mysql> explainselect * from yw_idx where c2 not in(4262384,3605632);

+----+-------------+--------+------+---------------+------+---------+------+---------+-------------+

| id | select_type |table  | type | possible_keys | key  | key_len | ref  | rows   | Extra       |

+----+-------------+--------+------+---------------+------+---------+------+---------+-------------+

|  1 | SIMPLE      | yw_idx | ALL  | idx_c2        | NULL | NULL    | NULL | 3016886 | Using where |

+----+-------------+--------+------+---------------+------+---------+------+---------+-------------+

1 row in set (0.10sec)

 

对其优化:

一般来说不能直接使用not in之类的sql语句,这属于病态sql

优化的时候可以加一个LIMIT,以减少IO

另外limit结果较大的话或者对其结果不满意的话,可以改为使用left join,然后用主建去关联id为b 而b.id 为null,如下所示:

mysql> select *from yw a left join ( select id from yw where c2 in (4262384, 3605632)) b ona.id=b.id where b.id is null limit 10;

 

+----+---------+---------+---------+---------+---------------------+------------------------------------------------------+------+

| id | c1      | c2     | c3      | c4     | c5                  | c6                                                  | id   |

+----+---------+---------+---------+---------+---------------------+------------------------------------------------------+------+

|  1 | 463681 | 1098981 | 1817518 | 2222359 | 2014-09-24 15:38:29 |wubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubx     | NULL |

|  2 | 2333997 | 269341 | 2459005 |  915557 |2014-09-24 15:38:29 | wubxwubxwubx                                         | NULL|

|  3 | 2971523 | 1226698 |  842469 | 414525 | 2014-09-24 15:38:29 | wubxwubxwubxwubxwubxwubxwubxwubxwubx                 | NULL |

|  4 | 2835700 | 930937 | 2835332 | 1945110 | 2014-09-24 15:38:29 | wubx                                                | NULL |

|  5 | 1578655 | 1044887 | 2649255 | 2307696 |2014-09-24 15:38:29 | wubxwubxwubxwubxwubxwubxwubx                         | NULL |

|  6 | 1442242 | 992011 | 1740281 |  190626 |2014-09-24 15:38:29 | wubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubx |NULL |

|  7 | 693798 |  309586 |  753637 | 2403923 | 2014-09-24 15:38:29 |wubxwubxwubxwubxwubxwubxwubxwubxwubxwubx             | NULL |

|  8 | 888272 | 2581335 | 1547343 | 1465295 | 2014-09-24 15:38:29 |wubxwubxwubxwubx                                     | NULL |

|  9 | 1608599 | 240304 | 2475805 | 2157717 | 2014-09-24 15:38:29 | wubxwubxwubxwubx                                     | NULL |

| 10 | 2833881 |  185188 | 1736996 |  565924 | 2014-09-24 15:38:29 |wubxwubxwubxwubxwubxwubxwubxwubxwubxwubx            | NULL |

+----+---------+---------+---------+---------+---------------------+------------------------------------------------------+------+

10 rows in set (17.04sec)

 

改为顺序IO

另外一种情况就是将其改为顺序IO去取前几行

只oder by id 将结果只取前10行,如果发现前10行已经能够满足需求的话,则将其取出不再做其他操作

mysql> select *from yw where c2 not in(4262384,3605632) order by id limit 10;

+----+---------+---------+---------+---------+---------------------+------------------------------------------------------+

| id | c1      | c2     | c3      | c4      | c5                 | c6                                                  |

+----+---------+---------+---------+---------+---------------------+------------------------------------------------------+

|  1 | 463681 | 1098981 | 1817518 | 2222359 | 2014-09-24 15:38:29 |wubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubx     |

|  2 | 2333997 | 269341 | 2459005 |  915557 |2014-09-24 15:38:29 | wubxwubxwubx                                         |

|  3 | 2971523 | 1226698 |  842469 | 414525 | 2014-09-24 15:38:29 | wubxwubxwubxwubxwubxwubxwubxwubxwubx                 |

|  4 | 2835700 | 930937 | 2835332 | 1945110 | 2014-09-24 15:38:29 | wubx                                                |

|  5 | 1578655 | 1044887 | 2649255 | 2307696 |2014-09-24 15:38:29 | wubxwubxwubxwubxwubxwubxwubx                         |

|  6 | 1442242 | 992011 | 1740281 |  190626 |2014-09-24 15:38:29 | wubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubxwubx |

|  7 | 693798 |  309586 |  753637 | 2403923 | 2014-09-24 15:38:29 |wubxwubxwubxwubxwubxwubxwubxwubxwubxwubx             |

|  8 | 888272 | 2581335 | 1547343 | 1465295 | 2014-09-24 15:38:29 |wubxwubxwubxwubx                                     |

|  9 | 1608599 | 240304 | 2475805 | 2157717 | 2014-09-24 15:38:29 | wubxwubxwubxwubx                                     |

| 10 | 2833881 |  185188 | 1736996 |  565924 | 2014-09-24 15:38:29 |wubxwubxwubxwubxwubxwubxwubxwubxwubxwubx             |

+----+---------+---------+---------+---------+---------------------+------------------------------------------------------+

10 rows in set (0.02sec)

 

只将结果集比较大的将其追加limit ,再去想办法对其优化

select * from yw a where a.id not in (select id from yw where id<100000) limit 100;

select * from yw a left join (select id from yw where id<100000) b  where a.id = b.id and b.id is null limit 100;

 

总结

MySQL支持什么样的索引以及这几种索引的区别是什么

MySQL支持 普通索引、组合索引、唯一索引、主键、全文索引、前缀索引(隶属于普通索引)

唯一索引:涉及到约束,包括在读的时间不会往下去读的

主建在innodb中作为一个聚集建所存在

短索引:短索引就是前缀索引,包含在普通索引中

 

当一个表里有一个int索引,varchar索引, 一个查询会么用到那个索引?(是先用int索引还是varchar索引呢?)

涉及到索引查询成本的理解

例:

select * from tbwhere c1_int=xxx and c2_varchar=xxx;

同样存在idx_c1和idx_c2

假设来讲: 总体查询成本是1, 基于int查询0.6 基于varchar 是0.7

实际来说基于varchar的是0.7那么,对于mysql来讲是选择任何一个索引;

如果查询成本1,那么其他两个都小于查询成本,那么都是可以的;

那么这时我们到底选择哪个完全取决于mysql的机制,mysql是按照先后的顺序进行选取

比如

create index varchar

首先创建varchar,那么,它会选择varchar,以此类推

所以,是根据其顺序进行选择的,也是mysql的机制

 

对其核心优化整体框架

核心概念: 减少IO

实际行动: 控制结果集大小,争取1秒内完成

减少IO,   考虑是否使用顺序IO

©著作权归作者所有:来自51CTO博客作者zuzhou的原创作品,如需转载,请注明出处,否则将追究法律责任

索引sql优化mysql优化数据库相关


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消