MySQL Explain 结果解读与实践

Explain 结果解读与实践

基于 MySQL 5.0.67 ,存储引擎 MyISAM 。

注:单独一行的"%%"及"`"表示分隔内容,就象分开“第一章”“第二章”。

explain 可以分析 select 语句的执行,即 MySQL 的“执行计划”:

mysql> explain select 1;

+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
| id | select_type | table | type | possible_keys | key  | key_len | ref  | rows | Extra          |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+
|  1 | SIMPLE      | NULL  | NULL | NULL          | NULL | NULL    | NULL | NULL | No tables used |
+----+-------------+-------+------+---------------+------+---------+------+------+----------------+

用"\G"代替分号可得到竖排的格式:

mysql> explain select 1\G
*************************** 1
           id: 1
  select_type: SIMPLE
        table: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: No tables used

`

可以用 desc 代替 explain :

desc select 1;

%%

id 列

建表:

create table a(a_id int);

create table b(b_id int);

create table c(c_id int);

mysql> explain select * from a join b on a_id=b_id where b_id in (select c_id from c);
+----+--------------------+-------+...
| id | select_type        | table |...
+----+--------------------+-------+...
|  1 | PRIMARY            | a     |...
|  1 | PRIMARY            | b     |...
|  2 | DEPENDENT SUBQUERY | c     |...
+----+--------------------+-------+...

从 3 个表中查询,对应输出 3 行,每行对应一个表, id 列表示执行顺序,id 越大,越先执行,id 相同,由上至下执行。此处的执行顺序为(以 table 列表示):c -> a -> b

%%

select_type 列

MySQL 把 SELECT 查询分成简单和复杂两种类型,复杂类型又可以分成三个大类:简单子查询、所谓的衍生表(子查询在 FROM 子句里)和 UNION 。

SIMPLE:查询中不包含子查询或者UNION

mysql> explain select * from a;
+----+-------------+-------+...
| id | select_type | table |...
+----+-------------+-------+...
|  1 | SIMPLE      | a     |...
+----+-------------+-------+...

SUBQUERY:子查询

PRIMARY:子查询上层

mysql> explain select * from a where a_id in (select b_id from b);
+----+--------------------+-------+...
| id | select_type        | table |...
+----+--------------------+-------+...
|  1 | PRIMARY            | a     |...
|  2 | DEPENDENT SUBQUERY | b     |...
+----+--------------------+-------+...

DERIVED:在FROM列表中包含子查询, MySQL 会递归执行这些子查询,把结果放在临时表里。

mysql> explain select count(*) from (select * from a) as der;
+----+-------------+-------+...
| id | select_type | table |...
+----+-------------+-------+...
|  1 | PRIMARY     | NULL  |...
|  2 | DERIVED     | a     |...
+----+-------------+-------+...

%%

table 列

显示每行对应的表名。若在 SELECT 语句中为表起了别名,则会显示表的别名。

一个很复杂的示例及解释可参考《高性能 MySQL 》(第二版)中文版 P467(pdf.491) 〈附录 B.2.3 table 列〉

%%

type 列

MySQL 在表里找到所需行的方式。包括(由左至右,由最差到最好):

| All | index | range | ref | eq_ref | const,system | null |

ALL

全表扫描,MySQL 从头到尾扫描整张表查找行。

mysql> explain select * from a\G

...

type: ALL

如果加上 limit 如 select * from a limit 10 MySQL 会扫描 10 行,但扫描方式不会变,还是从头到尾扫描。

`

index

按索引次序扫描表,就是先读索引,再读实际的行,其实还是全表扫描。主要优点是避免了排序,因为索引是排好序的。

建表:

create table a(a_id int not null, key(a_id));

insert into a value(1),(2)

mysql> explain select * from a\G
...
         type: index

`

range

以范围的形式扫描索引

建表:

create table a(a_id int not null, key(a_id));

insert into a values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);

mysql> explain select * from a where a_id > 1\G
...
         type: range

...

IN 比较符也会用 range 表示:

mysql> explain select * from a where a_id in (1,3,4)\G
...
         type: range
...

`

ref

非唯一性索引访问

建表:

create table a(a_id int not null, key(a_id));

insert into a values(1),(2),(3),(4),(5),(6),(7),(8),(9),(10);

mysql> explain select * from a where a_id=1\G
...
         type: ref

...

`

eq_ref

使用有唯一性索引查找(主键或唯一性索引)

建表及插入数据:

create table a(id int primary key);

create table a_info(id int primary key, title char(1));

insert into a value(1),(2);

insert into a_info value(1, ‘a‘),(2, ‘b‘);

mysql> explain select * from a join a_info using(id);
...+--------+--------+...
...| table  | type   |...
...+--------+--------+...
...| a      | index  |...
...| a_info | eq_ref |...
...+--------+--------+...

此时 a_info 每条记录与 a 一一对应,通过主键 id 关联起来,所以 a_info 的 type 为 eq_ref

删除 a_info 的主键:ALTER TABLE  `a_info` DROP PRIMARY KEY;

现在 a_info 已经没有索引了:

mysql> explain select * from a join a_info using(id);
+----+...+--------+--------+...

| id |...| table  | type   |...

+----+...+--------+--------+...

|  1 |...| a_info | ALL    |...

|  1 |...| a      | eq_ref |...

+----+...+--------+--------+...

这次 MySQL 调整了执行顺序,先全表扫描 a_info 表,再对表 a 进行 eq_ref 查找,因为 a 表 id 还是主键。

删除 a 的主键:alter table a drop primary key;

现在 a 也没有索引了:

mysql> explain select * from a join a_info using(id);
...+--------+------+...
...| table  | type |...
...+--------+------+...
...| a      | ALL  |...
...| a_info | ALL  |...
...+--------+------+...

现在两个表都使用全表扫描了。

建表及插入数据:

create table a(id int primary key);

create table a_info(id int, title char(1), key(id));

insert into a value(1),(2);

insert into a_info value(1, ‘a‘),(2, ‘b‘);

现在 a_info 表 id 列变为普通索引(非唯一性索引):

mysql> explain select * from a join a_info using(id) where a.id=1;
...+--------+-------+...
...| table  | type  |...
...+--------+-------+...
...| a      | const |...
...| a_info | ref   |...
...+--------+-------+...

a_info 表 type 变为 ref 类型了。

所以,唯一性索引才会出现 eq_ref (非唯一性索引会出现 ref ),因为唯一,所以最多只返回一条记录,找到后无需继续查找,因此比 ref 更快。

`

const

被称为“常量”,这个词不好理解,不过出现 const 的话就表示发生下面两种情况:

在整个查询过程中这个表最多只会有一条匹配的行,比如主键 id=1 就肯定只有一行,只需读取一次表数据便能取得所需的结果,且表数据在分解执行计划时读取。

返回值直接放在 select 语句中,类似 select 1 AS f 。可以通过 extended 选择查看内部过程:

建表及插入数据:

create table a(id int primary key, c1 char(20) not null, c2 text not null, c3 text not null);

insert into a values(1, ‘asdfasdf‘, ‘asdfasdf‘, ‘asdfasdf‘), (2, ‘asdfasdf‘, ‘asdfasdf‘, ‘asdfasdf‘);

mysql> explain extended select * from a where id=1\G
...
         type: const
possible_keys: PRIMARY
          key: PRIMARY
...

用 show warnings 查看 MySQL 是如何优化的:

mysql> show warnings\G
...
Message: select ‘1‘ AS `id`,‘asdfasdf‘ AS `c1`,‘asdfasdf‘ AS `c2`,‘asdfasdf‘ AS
`c3` from `test`.`a` where 1

查询返回的结果为:

mysql> select * from a where id=1;
+----+----------+----------+----------+
| id | c1       | c2       | c3       |
+----+----------+----------+----------+
|  1 | asdfasdf | asdfasdf | asdfasdf |
+----+----------+----------+----------+

可以看出,返回结果中的字段值都以“值 AS 字段名”的形式直接出现在优化后的 select 语句中。

修改一下查询:

mysql> explain select * from a where id in(1,2)\G
...
         type: range

...

当返回结果超过 1 条时, type 便不再为 const 了。

重新建表及插入数据:

create table a (id int not null);

insert into a value(1),(2),(3);

mysql> explain select * from a where id=1\G
...
         type: ALL

目前表中只有一条 id=1 的记录,但 type 已为 ALL ,因为只有唯一性索引才能保证表中最多只有一条记录,只有这样 type 才有可能为 const 。

为 id 加普通索引后, type 变为 ref ,改为加唯一或主键索引后, type 便变为 const 了。

相关阅读:

《高性能 MySQL 》第 2 版中文版

P130(pdf.153) 计算和减少常量表达式

P471(pdf.495) B.2.4 type 列

《 MySQL 性能调优与架构设计》

pdf.109

MySQL 帮助手册 7.2.1. EXPLAIN语法(获取SELECT相关信息)

`

system

system 是 const 类型的特例,当表只有一行时就会出现 system 。

建表及插入数据:

create table a(id int primary key);
insert into a value(1);

mysql> explain select * from a\G
...
         type: system

...

`

NULL

在优化过程中就已得到结果,不用再访问表或索引。

mysql> explain select min(a_id) from a\G
...
         type: NULL

...

%%

possible_keys 列

可能被用到的索引

建表:

create table a (a_id int primary key, a_age int, key (a_id, a_age));

此表有 主键及普通索引 两个索引。

mysql> explain select * from a where a_id=1\G
...
possible_keys: PRIMARY,a_id

%%

key 列

查询过程中实际使用的索引

mysql> explain select * from a where a_id=1\G
...
possible_keys: PRIMARY,a_id
          key: PRIMARY

%%

key_len 列

索引字段最大可能使用的长度。

mysql> explain select * from a where a_id=1\G
...
          key: PRIMARY
      key_len: 4

a_id 是 int 类型,int 的长度是 4 字节,所以 key_len 为 4。

%%

ref 列

指出对 key 列所选择的索引的查找方式,常见的值有 const, func, NULL, 具体字段名。当 key 列为 NULL ,即不使用索引时,此值也相应的为 NULL 。

建表及插入数据:

create table a(id int primary key, age int);

insert into a value(1, 10),(2, 10);

mysql> desc select * from a where age=10\G
...
          key: NULL
      key_len: NULL
          ref: NULL

...

当 key 列为 NULL , ref 列也相应为 NULL 。

mysql> explain select * from a where id=1\G

...
          key: PRIMARY
      key_len: 4
          ref: const

这次 key 列使用了主键索引,where id=1 中 1 为常量, ref 列的 const 便是指这种常量。

mysql> explain select * from a where id in (1,2)\G

...
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: NULL

...

不理解 ref 为 NULL 的含意,比如上面这个查询, key 列有使用索引,但 ref 列却为 NULL 。网上搜索及查阅了一下 MySQL 帮助手册都没有找到相关的描述。

再建表及插入数据:

create table a(id int primary key, a_name int not null);
create table b(id int primary key, b_name int not null);

insert into a value(1, 1),(2, 2),(3, 3);
insert into b value(1, 111),(2, 222),(3, 333);

mysql> explain select * from a join b using(id);
...+-------+--------+...+---------+...+-----------+...

...| table | type   |...| key     |...| ref       |...

...+-------+--------+...+---------+...+-----------+...

...| a     | ALL    |...| NULL    |...| NULL      |...

...| b     | eq_ref |...| PRIMARY |...| test.a.id |...

...+-------+--------+...+---------+...+-----------+...

这里 test.a.id 即为具体字段,意为根据表 a 的 id 字段的值查找表 b 的主键索引。

mysql> explain select * from a join b using(id) where b.id=1;
...+-------+-------+...+---------+...+-------+...

...| table | type  |...| key     |...| ref   |...

...+-------+-------+...+---------+...+-------+...

...| a     | const |...| PRIMARY |...| const |...

...| b     | const |...| PRIMARY |...| const |...

...+-------+-------+...+---------+...+-------+...

因为 a join b 的条件为 id 相等,而 b.id=1 ,就是 a.id 也为 1 ,所以 a,b 两个表的 ref 列都为 const 。

ref 为 func 的情况出现在子查询中,暂不明其原理:

mysql> explain select * from a where id in (select id from b where id in (1,2));

+----+--------------------+-------+...+---------+...+------+...

| id | select_type        | table |...| key     |...| ref  |...

+----+--------------------+-------+...+---------+...+------+...

|  1 | PRIMARY            | a     |...| NULL    |...| NULL |...

|  2 | DEPENDENT SUBQUERY | b     |...| PRIMARY |...| func |...

+----+--------------------+-------+...+---------+...+------+...

%%

rows 列

MySQL 估计的需要扫描的行数。只是一个估计。

%%

Extra 列

显示上述信息之外的其它信息,但却很重要。

Using index

此查询使用了覆盖索引(Covering Index),即通过索引就能返回结果,无需访问表。

若没显示"Using index"表示读取了表数据。

建表及插入数据:

create table a (id int primary key, age int);

insert into a value(1, 10),(2, 10);

mysql> explain select id from a\G
...
        Extra: Using index

因为 id 为主键索引,索引中直接包含了 id 的值,所以无需访问表,直接查找索引就能返回结果。

mysql> explain select age from a\G
...
        Extra:

age 列没有索引,因此没有 Using index ,意即需要访问表。

为 age 列添加索引:create index age on a(id, age);

mysql> explain select age from a\G
...
        Extra: Using index

现在索引 age 中也包含了 age 列的值,因此不用访问表便能返回结果了。

建表:create table a(id int auto_increment primary key, age int, name char(10));

插入 100w 条数据:insert into a value(null, rand()*100000000, ‘jack‘);

`

Using where

表示 MySQL 服务器从存储引擎收到行后再进行“后过滤”(Post-filter)。所谓“后过滤”,就是先读取整行数据,再检查此行是否符合 where 句的条件,符合就留下,不符合便丢弃。因为检查是在读取行后才进行的,所以称为“后过滤”。

建表及插入数据:

create table a (num_a int not null, num_b int not null, key(num_a));

insert into a value(1,1),(1,2),(2,1),(2,2);

mysql> explain select * from a where num_a=1\G
...
         type: ref
possible_keys: num_a
          key: num_a

key_len: 4
...
        Extra:

虽然查询中有 where 子句,但只有 num_a=1 一个条件,且 num_a 列存在索引,通过索引便能确定返回的行,无需进行“后过滤”。

所以,并非带 WHERE 子句就会显示"Using where"的。

mysql> explain select * from a where num_a=1 and num_b=1\G
...
         type: ref
possible_keys: num_a
          key: num_a
...
        Extra: Using where

此查询增加了条件 num_b=1 ,此列没有索引,但可以看到查询同样能使用 num_a 索引。 MySQL 先通过索引 num_a 找到 num_a=1 的行,然后读取整行数据,再检查 num_b 是否等于 1 ,执行过程看上去象这样:

num_a索引|num_b 没有索引,属于行数据

+-------+-------+
| num_a | num_b | where 子句(num_b=1)
+-------+-------+
|     1 |     1 | 符合
|     1 |     2 | 不符合
|   ... |   ... | ...
+-------+-------+

在《高性能 MySQL 》(第二版)P144(pdf.167) 页有更形象的说明图片(图 4-5 MySQL 通过整表扫描查找数据)。

字段是否允许 NULL 对 Using where 的影响:

建表及插入数据:

create table a (num_a int null, num_b int null, key(num_a));

insert into a value(1,1),(1,2),(2,1),(2,2);

这次 num_a, num_b 字段允许为空。

在上例 num_a not null 时, num_a 索引的长度 key_len 为 4 ,当 num_a null 时, num_a 索引的长度变为了 5 :

mysql> explain select * from a where num_a=1\G
...
         type: ref
possible_keys: num_a
          key: num_a
      key_len: 5
...
        Extra: Using where

并且哪怕只有 num_a=1 一个条件,也会出现 Using where 。原因暂不明白。

`

Using temporary

使用到临时表

建表及插入数据:

create table a(a_id int, b_id int);

insert into a values(1,1),(1,1),(2,1),(2,2),(3,1);

mysql> explain select distinct a_id from a\G
...
        Extra: Using temporary

MySQL 使用临时表来实现 distinct 操作。

`

Using filesort

若查询所需的排序与使用的索引的排序一致,因为索引是已排序的,因此按索引的顺序读取结果返回,否则,在取得结果后,还需要按查询所需的顺序对结果进行排序,这时就会出现 Using filesort 。

建表及插入数据:

create table a(a_id int, b_id int);

insert into a values(1,1),(1,1),(2,1),(2,2),(3,1);

mysql> explain select * from a order by a_id\G
...
        Extra: Using filesort

对于没有索引的表,只要 order by 必会出现 Using filesort 。

现在增加索引:create index a_id on a(a_id);

把表 a 的记录增加到约 100w(1048576) 条, a_id 与 b_id 都是随机生成的数字:

mysql> select * from a order by rand() limit 10;
+-------+--------+
| a_id  | b_id   |
+-------+--------+
| 61566 | 961297 |
| 33951 | 680542 |

| ..... | ...... |
+-------+--------+

mysql> explain select * from a order by a_id\G
...
         type: ALL
...

rows: 1048576
        Extra: Using filesort

同样是 Using filesort ,type 为 ALL ,全表扫描。听说“取全表数据根据ID排序,走索引一定不如直接查,因为可以减少因为需要索引改变数据访问顺序造成随机IO的概率,数据库放弃索引是应该的”,参考:

http://isky000.com/database/mysql_order_by_implement#comment-2981

当 type 为 rang、 ref 或者 index 的时候才有可能利用索引排序,其它,如 ALL ,都无法通过索引排序,此时若有 order by ,如上例,便会出现 Using filesort 。

现在增加 where 子句:

mysql> explain select * from a where a_id=10 order by a_id\G
...
         type: ref
possible_keys: a_id
          key: a_id
...

rows: 8
        Extra:

查询走了索引 a_id ,此时 type 为 ref ,直接按索引顺序返回,没有 Using filesort 。

修改 where 子句:

mysql> explain select * from a where a_id>10 and a_id<100 order by a_id\G
...
         type: range
possible_keys: a_id
          key: a_id
...
         rows: 712
        Extra: Using where

同样利用索引排序,没有 Using filesort 。

再修改 where 子句:

mysql> explain select * from a where a_id >10 order by a_id\G
...
         type: ALL
possible_keys: a_id
          key: NULL
...
         rows: 1048576
        Extra: Using where; Using filesort

又出现 Using filesort 且 type 变为 ALL 。注意以上例子的 rows 列,此列表示 MySQL 估计查询需要读取的行数,分别为 1048576, 8, 712, 1048576 ,特别注意最后两个数字: 712, 1048576 。

可见,当索引能为查询排除大部份行时( a_id=10 时约读取 8 行,排除了大部份, a_id>10 and a_id<100 时约读取 712 行,同样排除了大部份)便使用索引,否则,如 a_id>10 时约读取 1048576 , MySQL 直接改用全表扫描,再 Using filesort 。也就是说, MySQL 会根据表中的信息及查询来决定使用任种方式。

关于 MySQL 读取数据表的方式,可参考(暂缺参考资料),就会明白为什么需读取 1048576 行时,先读索引再读表数据还不如全表扫描了。

对于多字段排序(order by a, b)及带 group by 的查询,可参考 MySQL 帮助手册 7.2.12. MySQL如何优化ORDER BY 。

%%

参考资料:

MySQL 帮助手册

7.2.1. EXPLAIN语法(获取SELECT相关信息)

7.2.12. MySQL如何优化ORDER BY

《高性能 MySQL 》(第二版)中文版

P463(pdf.487) 附录 B

《 MySQL 性能调优与架构设计》

MySQL ORDER BY 的实现分析

http://isky000.com/database/mysql_order_by_implement

Mysql执行计划

http://www.xifenfei.com/954.html

MySQL执行计划解读

http://wenku.baidu.com/view/41846439376baf1ffc4fad4f.html

Mysql Explain 详解

http://www.cnitblog.com/aliyiyi08/archive/2008/09/09/48878.html

MYSQL EXPLAIN语句的extended 选项学习体会

http://hi.baidu.com/dearhwj/blog/item/03badf17641a28094a90a78d.html

Show Warnings

%%

MySQL索引类型一览 让MySQL高效运行起来

http://database.51cto.com/art/200910/156685.htm

Mysql执行计划中的Using filesort

"指出Mysql可以使用哪个索引在该表中找到行"

http://www.taobaodba.com/html/235_mysql_using_filesort.html

2.order by b,如果b列不在索引中,不管b值是否相同,总会出现Using filesort。

%%

What does Using filesort mean in MySQL?

"任何不能通过index进行的sort都称之为filesort"

http://iceskysl.1sters.com/?p=638

mysql explain中的using filesort

"只能是如果可能的话修改查询的排序条件"

http://blog.csdn.net/wdwbw/article/details/5256064

Mysql之EXPLAIN显示using filesort

"结果昨天看到公司的一个"

http://www.ccvita.com/169.html(可能这个是出处)

多列索引在建立的时候是以B-树结构建立的,因此建立索引的时候是先建立ID的按顺序排的索引,在相同ID的情况下建立FID按 顺序排的索引,最后在FID 相同的情况下建立按INVERSE_DATE顺序排的索引,如果列数更多以此类推。

要在优化一下这个sql就应该为它建立另一个索引IDX(ID,INVERSE_DATE),这样就消除了using filesort速度也会快很多。

%%

mysql优化Using filesort

"并且用到了room_number这列索引"

http://www.askwan.com/post/151/

MySQL 索引 优化 Using filesort

"页面咔的一下就出来了"

http://www.leakon.com/archives/332

时间: 2024-10-12 03:00:18

MySQL Explain 结果解读与实践的相关文章

【MySQL】锁问题最佳实践

最近一段时间处理了较多锁的问题,包括锁等待导致业务连接堆积或超时,死锁导致业务失败等,这类问题对业务可能会造成严重的影响,没有处理经验的用户往往无从下手.下面将从整个数据库设计,开发,运维阶段介绍如何避免锁问题的发生,提供一些最佳实践供读者参考. 设计阶段 在数据库设计阶段,引擎选择和索引设计不当可能导致后期业务上线后出现较为严重的锁或者死锁问题. 1. 表引擎选择使用myisam,引发table level lock wait. 从5.5版本开始,MySQL官方就把默认引擎由myisam转为i

MySQL执行计划解读

MySQL执行计划解读 http://www.cnblogs.com/ggjucheng/archive/2012/11/11/2765237.html MySQL执行计划解读 Explain语法 EXPLAIN SELECT -- 变体: 1. EXPLAIN EXTENDED SELECT -- 将执行计划"反编译"成SELECT语句,运行SHOW WARNINGS 可得到被MySQL优化器优化后的查询语句 2. EXPLAIN PARTITIONS SELECT -- 用于分区表

MySQL执行计划解读(转载)

MySQL执行计划解读 Explain语法 EXPLAIN SELECT …… 变体: 1. EXPLAIN EXTENDED SELECT …… 将执行计划“反编译”成SELECT语句,运行SHOW WARNINGS 可得到被MySQL优化器优化后的查询语句 2. EXPLAIN PARTITIONS SELECT …… 用于分区表的EXPLAIN 执行计划包含的信息 id 包含一组数字,表示查询中执行select子句或操作表的顺序 id相同,执行顺序由上至下 如果是子查询,id的序号会递增,

Mysql Explain 详解

一.语法 explain < table_name > 例如: explain select * from t3 where id=3952602; 二.explain输出解释 +----+-------------+-------+-------+-------------------+---------+---------+-------+------+-------+| id | select_type | table | type  | possible_keys     | key 

MySQL EXPLAIN Output Format(MySQL运维神技)

摘要: DBA经常会用到的explain来查看SQL语句的执行计划,今天小人斗胆,从MySQL 5.7 Reference Manual中把MySQL EXPLAIN Output Format翻译过来.欢迎拍砖 Explain语句提供了一个select语句执行计划的信息. Explain为每个用了select语句的表,返回一行信息.它列出了表中的顺序输出,MySQL会读取他们,然后再处理.MySQL解决了所有使用嵌套循环连接方法.这意味着MySQL会读取第一个表中的一行,然后在第二个表中找到一

MySQL Explain详解(转)

explain SELECT a.* FROM test a,(select id from test where level_id <=4 order by aa_id limit 243000, 100) b where a.id=b.id ;因为延迟关联通过覆盖索引返回所需数据行的主键,再根据主键关联原表获得需要的数据,所以速度比之前快上不少. 覆盖索引(只访问索引的查询,即查询只需要访问索引,而无须访问数据行,最简单的理解,比如翻开一本书,从目录页查找某些内容,但是目录就写的比较详细,我

mysql乐观锁总结和实践

上一篇文章<MySQL悲观锁总结和实践>谈到了MySQL悲观锁,但是悲观锁并不是适用于任何场景,它也有它存在的一些不足,因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性.如果加锁的时间过长,其他用户长时间无法访问,影响了程序的并发访问性,同时这样对数据库性能开销影响也很大,特别是对长事务而言,这样的开销往往无法承受.所以与悲观锁相对的,我们有了乐观锁,具体参见下面介绍: 乐观锁介绍: 乐观锁( Optimistic Locking ) 相对悲观锁而言,乐观锁假设认为数据

mysql乐观锁总结和实践(转)

原文:mysql乐观锁总结和实践 上一篇文章<MySQL悲观锁总结和实践>谈到了MySQL悲观锁,但是悲观锁并不是适用于任何场景,它也有它存在的一些不足,因为悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性.如果加锁的时间过长,其他用户长时间无法访问,影响了程序的并发访问性,同时这样对数据库性能开销影响也很大,特别是对长事务而言,这样的开销往往无法承受.所以与悲观锁相对的,我们有了乐观锁,具体参见下面介绍: 乐观锁介绍: 乐观锁( Optimistic Locking )

mysql explain 命令解释

转载http://bzyyc.happy.blog.163.com/blog/static/6143064720115102551554/ key实 际使用的索引.如果为NULL,则没有使用索引.很少的情况下,MYSQL会选择优化不足的索引.这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MYSQL忽略索引 key_len使用的索引的长度.在不损失精确性的情况下,长度越短越好 mysql