查看命令html
a. 查看所使用的MySQL如今已提供什么存储引擎:java
mysql> show engines;mysql
b. 查看所使用的MySQL当前默认的存储引擎:ios
mysql> show variables like '%storage_engine%';程序员
MyISAM和InnoDB两种存储引擎的区别算法
对比项 | MyISAM | InnoDB |
---|---|---|
主外键 | 不支持 | 支持 |
事务 | 不支持 | 支持 |
行表锁 | 表锁,即便操纵一条记录也会锁住整个表,不适合高并发的操做 | 行锁,操做时只锁某一行,不对其余行有影响,适合高并发的操做 |
缓存 | 只缓存索引,不缓存真实数据 | 不只缓存索引还要缓存真实数据,对内存要求较高,并且内存大小对性能有决定性的影响 |
表空间 | 小 | 大 |
关注点 | 性能 | 事务 |
默认安装 | Y | Y |
事务隔离级别
“脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数据库提供必定的事务隔离机制来解决。sql
读数据一致性及容许的并发反作用 | 读数据一致性 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|---|
Read uncommitted | 最低级别,只能保证不读取物理上损坏的数据 | 是 | 是 | 是 |
Read committed | 语句级 | 否 | 是 | 是 |
Repeatable read | 事务级 | 否 | 否 | 是 |
Serializable | 最高级别,事务级 | 否 | 否 | 否 |
数据库的事务隔离越严格,并发反作用越小,但付出的代价也就越大,由于事务隔离实质上就是使事务在必定程度上,“串行化”进行,这显然与“并发”是矛盾的。同时,不一样的应用对读一致性和事务隔离程度的要求也是不一样的,好比许多应用对“不可重复读”和“幻读”并不敏感,可能更关心数据并发访问的能力。
查看MySQL的事务隔离级别:show variables like 'tx_isolation';
数据库
包括但不限于下列状况:缓存
MySQL官方对索引的定义为:索引(Index)是帮助MySQL高效获取数据的数据结构。能够获得索引的本质:索引是数据结构。
索引的目的在于提升查询效率,能够类比字典,好比:若是要查“MySQL”这个单词,咱们确定须要定为到m字母,而后从上往下找到y字母,再找到剩下的s、q、l。若是没有索引,那么你可能须要a--z,若是我想找到Java开头的单词呢?或者Oracle开头的单词呢?是否是以为若是没有索引,这个事情根本没法完成?
你能够简单理解为“排好序的快速查找的数据结构”。服务器
详解
在数据以外,数据库系统还维护着知足特定查找算法的数据结构,这些数据结构以某种方式引用(指向)数据,这样就能够在这些数据结构上实现高级查找算法。这种数据结构,就是索引。下图就是一种可能的索引方式示例:
为了加快Col2的查找,能够维护一个右边所示的二叉查找树,每一个节点分别包含索引键值和一个指向对应数据的记录物理地址的指针,这样就能够运用二叉查找在必定的复杂度内获取到相应数据,从而快速的检索出符合条件的记录。
结论
数据自己以外,数据库还维护着一个知足特定查找算法的数据结构,这些数据结构以某种方式指向数据,这样就能够在这些数据结构的基础上实现高级算法,这种数据结构就是索引。
通常来讲,索引自己也很大,不可能所有存储在内存中,所以索引每每以索引文件的形式存储在磁盘上。
咱们日常所说的索引,若是没有特别指明,都是指B树(多路搜索树,并不必定是二叉树)结构组织的索引。其中汇集索引,次要索引,覆盖索引,复合索引,前缀索引,惟一索引默认都是使用B+数索引,统称索引。固然,除了B+树这种类型的索引以外,还有哈希索引(hash index)等。
优点
相似大学图书馆创建书目索引,提升数据检索的效率,下降数据库的IO成本。经过索引列对数据进行排序,下降数据排序的成本,下降了CPU的消耗。
劣势
实际上索引也是一张表,该表保存了主键与索引字段,并指向实体表的记录,因此索引列也是要占用空间的。
虽然索引大大提升了查询速度,同时却会下降更新表的速度,如对表进行INSERT
、UPDATE
和DELETE
。由于更新表时,MySQL不只要保存数据,还要保存一下索引文件每次更新添加了索引列的字段。
索引只是提升效率的一个因素,若是你的MySQL有大数据量的表,就须要花时间创建最优秀的索引,或优化查询。
MySQL索引分类
创建复合索引优于创建单值索引。通常而言,一张表最多建5个索引
基本语法
CREATE [UNIQUE] INDEX indexName ON mytable(columnname(length));
ALTER mytable ADD [UNIQUE] INDEX [indexName] ON (columnname(length));
DROP INDEX [indexName] ON mytable;
SHOW INDEX FROM table_name;
ALTER TABLE tbl_name ADD PRIMARY KEY(column_list);
该语句添加一个主键,这意味着索引值必须是惟一的,且不能为NULL;ALTER TABLE tbl_name ADD UNIQUE index_name(column_list);
这条语句建立索引的值必须是惟一的(除了NULL外,NULL可能会出现屡次);ALTER TABLE tbl_name ADD INDEX index_name(column_list);
添加普通索引,索引值可出现屡次;ALTER TABLE tbl_name ADD FULLTEXT index_name(column_list);
该语句指定了索引为FULLTEXT,用于全文索引。Btree
尽可能增长检索广度,不增长深度。检索原理:
R-Tree
INSERT
、UPDATE
和DELETE
。由于更新表时,MySQL不只要保存数据,还要保存一下索引文件。MySQL Query Optimizer
时,MySQL Query Optimizer
首先会对整条Query进行优化,处理掉一些常量表达式的预算,直接换算成常量值。并对Query中的查询条件进行简化和转换,如去掉一些无用或显而易见的条件、结构调整等。而后分析Query中的Hint信息(若是有),看现实Hint信息是否能够彻底肯定该Query的执行计划。若是没有Hint或Hint信息还不足以彻底肯定执行计划,则会读取所涉及对象的统计信息,根据Query进行写相应的计算分析,而后再得出最后的执行计划。top
, free
, iostat
和vmstat
来查看系统的性能状态。使用EXPLAIN关键字能够模拟优化器执行SQL查询语句,从而知道MySQL是如何处理你的SQL语句的。分析你的查询语句或是表结构的性能瓶颈。
官网介绍
包含的信息
id
select
查询的序列号,包含一组数字,表示查询中执行select
子句或操做表的顺序。包含三种状况:
id
相同,执行顺序由上至下
id
不一样,若是是子查询,id
的序号会递增,id
值越大优先级越高,越先被执行
id
相同和不一样,同时存在
id
若是相同,能够认为是一组,从上往下顺序执行,在全部组中,id
值越大,优先级越高,越先执行。select_type
SIMPLE
,PRIMARY
,SUBQUERY
,DERIVED
,UNION
,UNION RESULT
,主要是用于区别普通查询、联合查询、子查询等复杂查询。
select
查询,查询中不包含子查询或者UNION
PRIMARY
SELECT
或者WHERE
列表中包含了子查询FROM
列表中包含的子查询被标记为DERIVED
(衍生),MySQL会递归执行这些子查询,把结果放在临时表里SELECT
出如今UNION
以后,则被标记为UNION
,若UNION
包含在FROM
子句的子查询中,外层SELECT将被标记为:DERIVED
UNION
表获取结果的SELECT
table
type
ALL
,index
,range
,ref
,eq_ref
,const,system
,NULL
。system > const > eq_ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
system > const > eq_ref > ref > range > index > ALL
const
类型的特例,平时不会出现,这个也能够忽略不计const
用于比较primary key
或者unique
索引,由于只匹配一行数据,因此很快,如将主键置于where
列表中,MySQL就能将该查询转换为一个常量eq_ref:惟一性索引扫描,对于每一个索引键,表中只有一条记录与之匹配。常见于主键或惟一索引扫描
ref:非惟一性索引扫描,返回匹配某个单独值的全部行。
本质上也是上也是一种索引访问,它返回全部匹配某个单独值的行,然而,它可能会找到多个符合条件的行,因此它应该属于查找和扫描的混合体
range:只检索给定范围的行,使用一个索引来选择行。
key
列显示使用了哪一个索引,通常就是在你的where
语句中出现了between
、<
、>
、in
等的查询,这种范围扫描索引扫描比全表扫描要好,由于它只须要开始于索引的某一点,而结束语另外一点,不用扫描所有索引。以下:
Full Index Scan
,index
与ALL
的区别为index
类型只遍历索引树,这一般比ALL
块,由于索引文件一般比数据文件小。(也就是说虽然ALL
和index
都是读全表,但index
是从索引中读取的,而ALL是从硬盘中读的)Full Table Scan
,将遍历全表以找到匹配的行possible_keys
key
实际使用的索引。若是为NULL
,则没有使用索引。查询中若使用了覆盖索引,则该索引仅出如今key
列表中。以下:
先创建索引:
create index idx_col1_col2 on t2(col1, col2);
而后使用explain语句分析下列SQL语句:
key_len
key_len
显示的值为索引字段的最大可能长度,并不是实际使用长度,即key_len是根据表定义计算而得,不是经过表内检索出的。ref
idx_col1_col2
被充分使用,col1
匹配t2表的col1
,col2匹配了一个常量,即‘ac’。rows
根据表统计信息及索引选用状况,大体估算出找到所需的记录所须要读取的行数。以下,观察创建索引先后rows的变化:
Extra
Using filesort
,该SQL语句会执行得比较慢,须要对其进行优化。order by
和分组查询group by
。Using temporary
,那么该SQL语句会更慢,需对其进行优化。select
操做中使用了覆盖索引(Covering Index),避免访问了表的数据行,效率不错!若是同时出现Using where
,代表索引被用来执行索引键值的查找;若是没有同时出现Using where
,代表索引被用来读取数据而非执行查找动做。Using where
,代表索引被用来执行索引键值的查找;Using where
,代表索引用来读取数据而非执行查找动做。select
的数据列只用从索引中就可以取得,没必要读取数据行,MySQL能够利用索引返回select
列表中的字段,而没必要根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖。select
列表中只取出须要的列,不可select *
,由于若是将全部字段一块儿作索引会致使索引文件过大,查询性能降低。where
过滤。impossible where:where
子句的值老是false
,不能用来获取任何元组。如:
GROUP BY
子句的状况下,基于索引优化MIN/MAX操做或者对于MyISAM存储引擎优化COUNT(*)
操做,没必要等到执行阶段再进行计算,查询执行计划生成的阶段即完成优化。distinct:(出现频率很小)优化distinct
操做,在找到第一匹配的元组后即中止找一样的动做。
第一行(执行顺序4):id
列为1,表示是union
里的第一个select
,select_type
列的primary
表示该查询为外层查询,table
列被标记为<derived3>
,表示查询结果里来自一个衍生表,其中derived3
中3表明该查询衍生自第三个select
查询,即id
为3的select
。select d1.name ......
第二行(执行顺序2):id
为3,是整个查询中第三个select
的一部分,因查询包含在from
中,因此为derived
。select id, name from t1 where other_column="
第三行(执行顺序3):select
列表中的子查询select_type
为subquery
,为整个查询中的第二个select
。select id from t3
第四行(执行顺序1):select_type
为union
,说明第四个select
是union
里的第二个select
,最早执行。select name, id from t2
第五行(执行顺序5):表明从union
的临时表中读取行的阶段,table
列的<union1,4>
表示用第一个和第四个select
的结果进行。
explain select id, author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
type
是ALL
,即最坏的状况,Extra
里还出现了Using filesort
,也是最坏的状况。必需要进行优化。alter table article add index idx_article_ccv(category_id, comments, views);
或create index idx_article_ccv on article(category_id, comments, views);
explain select id, author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
type
为range
,这是能够忍受的。可是extra
里使用Using filesort
还是没法接受的。category_id
,若是遇到相同的category_id
,则再排序comments
,若是遇到相同的comments
则再排序views。comments
字段在联合索引里处于中间位置时,因comments > 1
条件是一个范围值(所谓range
),MySQL没法利用索引再对后面的views
部分进行检索,即range
类型查询字段后面的索引无效。
drop index idx_article_ccv on article;
alter table article add index idx_article_cv(category_id, views);
或create index idx_article_cv on article(category_id, views);
explain
explain select id, author_id from article where category_id = 1 and comments > 1 order by views desc limit 1;
type
变为了ref
,Extra
中的Using filesort
也消失了,结果很是理想。insert into class(card) values(floor(1 + (rand() * 20)));
insert into book(card) values(floor(1 + (rand() * 20)));
explain select * from class left join book on class.card = book.card;
结论:type中有ALL。
添加索引进行优化:alter table book add index y(card);
再次进行explain分析:
能够看到第二行的type
变为了ref
,rows
优化也比较明显。 这是由左链接特性决定的。left join
条件用于肯定如何从右表搜索行,左边必定都有,因此右边是咱们的关键点,必定须要创建索引。
删除旧索引,而后创建新的索引,再进行第3次explain
insert into phone(card) values(floor(1 + (rand() * 20)));
alter table phone add index z(card);
alter table book add index y(card);
后两行的type
都是ref
,且总的rows
优化很好,效果不错,所以索引最好设置在须要常常查询的字段中。
Join语句的优化
Join
语句中的NestedLoop
的循环总次数:“永远用小结果集驱动大的结果集”;NestedLoop
的内层循环;Join
条件字段已经被索引;Join
条件字段被索引且内存资源充足的前提下,不要太吝啬JoinBuffer
的设置。insert into staffs(name, age, pos, add_time) values('z3', 22, 'manager', now());
insert into staffs(name, age, pos, add_time) values('july', 23, 'dev', now());
insert into staffs(name, age, pos, add_time) values('tom', 23, 'dev', now());
ALTER TABLE staffs ADD INDEX idx_staffs_nameAgePos(name,age,pos);
全值匹配
不在索引列上作任何操做(计算、函数、(自动or手动)类型转换),会致使索引失效而转向全表扫描
存储引擎不能使用索引中范围条件右边的列
is null
,is not null
也没法使用索引‘%abc…’
)MySQL索引失效会变成全表扫描的操做explain select id from tbl_user where name like '%aa%;
explain select name from tbl_user where name like '%aa%;
explain select age from tbl_user where name like '%aa%;
explain select id, name from tbl_user where name like '%aa%;
explain select id, name, age from tbl_user where name like '%aa%;
explain select name, age from tbl_user where name like '%aa%;
explain select * from tbl_user where name like '%aa%;
explain select id, name, age, email from tbl_user where name like '%aa%;
create index idx_user_nameAge on tbl_user(name, age);
explain
,除了最后两条select *
即查询列多出了索引外的email
字段,其他都利用了覆盖索引或直接使用了主键索引,效果都会挺好。小总结
全值匹配我最爱,最左前缀要遵照;
带头大哥不能死,中间兄弟不能断;
索引列上少计算,范围以后全失效;
Like百分写最右,覆盖索引不写星;
不等空值还有or,索引失效要少用;
VAR引号不可丢,SQL高级也不难。
假设index(a, b, c):下表中的各类状况,可自行试验。
where语句 | 索引是否被使用 | |
---|---|---|
where a = 3 | Y,使用到a | |
where a = 3 and b = 5 | Y,使用到a,b | |
where a = 3 and b = 5 and c = 4 | Y,使用到a,b,c | |
where b = 3 或者 where b = 3 and c = 4 或者 where c = 4 | N | |
where a = 3 或者 c = 5 | 使用到a,可是c不能够,b中间断了 | |
where a = 3 and b > 4 and c = 5 | 使用到a和b,c不能用在范围以后,b断了 | |
where a = 3 and b like 'kk%' and c = 4 | Y,使用到a,b,c | |
where a = 3 and b like '%kk' and c = 4 | Y,只用到a | |
where a = 3 and b like '%kk%' and c = 4 | Y,只用到a | |
where a = 3 and b like 'k%kk%' and c = 4 | Y,使用到a,b,c |
小表驱动大表,即小的数据集驱动大的数据集。
select * from A where id in (select id from B) 等价于 for select id from B for select * from A where A.id = B.id
当B表的数据集必须小于A表的数据集时,用in优于exists。
select * from A where exists (select 1 from B where B.id = A.id) 等价于 for select * from A for select * from B where B.id = A.id
当A表的数据集系小于B表的数据集时,用exists优于in。
注意:A表与B表的id字段应创建索引。
select ... from table where exists (subquery);
exists(subquery)
只返回true或false,所以子查询中的select *
也能够是select 1
或其余,官方说法是实际执行时会忽略select
清单,所以没有区别exists
子查询的实际执行过程可能通过了优化而不是咱们理解上的逐条对比,若是担心效率问题,可进行实际检验以肯定是否有效率问题exists
子查询每每也能够用条件表达式、其余子查询或者join
来替代,何种最优须要具体问题具体分析order by
子句,尽可能使用index
方式排序,避免使用filesort
方式排序
建表SQL + 添加数据 + 创建索引
case
filesort
和index
,index
效率高,它指MySQL扫描索引自己完成排序,filesort
方式效率较低order by
知足两种状况,会使用index方式排序:
order by
语句使用索引最左前列where
子句与order by
子句条件列组合知足索引最左前列filesort
有两种算法,MySQL就要启动双路排序和单路排序
order by
列,对他们进行排序,而后扫描已经排序好的列表,按照列表中的值从新从列表中读取对应的数据输出。buffer
进行排序,再从磁盘取其余字段。order by
列在buffer
对它们进行排序,而后扫描排序后的列表进行输出,它的效率更快一些,避免了第二次读取数据。而且把随机IO变成了顺序IO,可是它会使用更多的空间,由于它把每一行都保存在内存中了。sort_buffer
中,方法B比方法A要占用不少空间,由于方法B是把全部字段都取出,因此有可能取出的数据的总大小超出了sort_buffer
的容量,致使每次只能取sort_buffer
容量大小的数据,进行排序(建立tmp文件,多路合并),排完再去取sort_buffer
容量大小,再排......从而屡次I/O。sort_buffer_size
参数的的设置max_length_for_sort_data
参数的设置order by
的时候,select *
是一个大忌,所以只查询须要的字段,这点很是重要,在这里影响的是:
max_length_for_sort_data
并且排序字段不是text
|blob
类型时,会用改进后的算法--单路排序,不然用老算法--多路排序sort_buffer
的容量,超出以后,会建立tmp文件进行合并排序,致使屡次I/O,可是用单路排序算法的风险会更大一些,因此要提升sort_buffer_size
sort_buffer_size
max_length_for_sort_data
sort_buffer_size
的几率就增大,明显症状是高的磁盘I/O活动和低的处理器使用率小总结
key:a_b_c(a, b, c)
order by能使用索引最左前缀
order by a
order by a,b
order by a,b,c
order by a desc,b desc,c desc #这个同时都为降序因此也能够若是where使用索引的最左前缀定义为常量,则order by能使用索引
where a=const order by b,c
where a=const and b=const order by c
where a=const order by b,c
where a=const and b>const order by b,c不能使用索引进行排序
order by a asc,b desc,c desc #排序不一致,有升序有降序
where g=const order by b,c #丢失a索引,没有带头大哥
where a=const order by c #丢失b索引
where a in(...) order by b,c #对于排序来讲,多个相等条件也是范围查询
group by
实质是先排序后进行分组,遵守索引建的最佳左前缀max_length_for_sort_data
参数的设置加增大sort_buffer_size
参数的设置where
高于having
,能写在where
限定的条件就不要去having
限定了MySQL的慢查询日志是MySQL提供的一种日志记录,它用来记录在MySQL中响应时间超过阀值的语句,具体指运行时间超过long_query_time
值的SQL,则会被记录到慢查询日志中。long_query_time
的默认值为10,意思是运行10秒以上的语句。
用它来查看哪些SQL超出了咱们的最大忍耐时间值,好比一条SQL执行超过5秒钟,咱们就把它定为慢SQL,但愿能收集超过5秒钟的SQL,结合以前的explain
进行全面分析。
默认
show varialbes like '%slow_query_log%';
经过执行上条语句,能够看到,默认状况下,slow_query_log
的值为OFF
,表示慢查询日志是禁用的。能够经过设置slow_query_log
的值来开启。
set global slow_query_log=1;
set global slow_query_log=1
开启了慢查询日志,只对当前数据库生效,而且若是MySQL重启后则会失效。my.cnf
(其它系统变量也是如此)my.cnf
文件,[mysqld]下增长或修改参数slow_query_log
和slow_query_log_file
后,而后重启MySQL服务器。也即,将以下两行配置进my.cnf
文件slow_query_log=1
slow_query_log_file=/usr/local/mysql/data/chengchangfudeMacBook-Pro-slow.log
slow_query_log_file
,它指定慢查询日志文件的存放路径,系统默认会给一个缺省的文件 host_name_slow.log
(若是没有指定参数slow_query_log_file
的话)。long_query_time
控制的,默认状况下long_query_time
的值为10秒,命令:show variables like 'long_query_time%';
long_query_time
的状况,并不会被记录下来。也就是说,在MySQL源码里是判断大于long_query_time
,而非大于等于。show variables like 'long_query_time%';
set global long_query_time=3;
记录慢查询并分析
查询当前系统中有多少条慢查询记录
[mysqld]
下配置:在生产环境中,若是要手工分析日志,查找、分析SQL,显然是个体力活,MySQL提供了日志分析工具:mysqldumpslow
。
查看mysqldumpslow
的帮助信息
使用mysqldumpslow --help
命令进行查看
s:是表示按照何种方式排序;
c:访问次数
l:锁定时间
r:返回记录
t:查询时间
al:平均锁定时间
ar:平均返回记录数
at:平均查询时间
t:即为返回前面多少条的数据;
g:后边搭配一个正则匹配模式,大小写不敏感的;
工做经常使用参考
获得返回记录集最多的10个SQL
mysqlddumpslow -s r -t 10 chengchangfudeMacBook-Pro-slow.log
获得访问次数最多的10个SQL
mysqlddumpslow -s c -t 10 chengchangfudeMacBook-Pro-slow.log
获得按照时间排序的前10条里面含有左链接的查询语句
mysqlddumpslow -s t -t 10 -g "left join" chengchangfudeMacBook-Pro-slow.log
另外建议在使用这些命令时结合|
和more
使用,不然有可能出现爆屏状况
mysqlddumpslow -s r -t 10 chengchangfudeMacBook-Pro-slow.log | more
Show Profile
是MySQL提供能够用来分析当前会话中语句执行的资源消耗状况。能够用于SQL调优的测量。
官网介绍
默认状况下,参数处于关闭状态,并保存最近15次的运行结果,使用set profiling=on;
进行开启
select * from emp group by id%10 limit 150000;
select * from emp group by id%20 order by 5;
诊断SQL
show profile cpu, block io for query 上一步前面的问题SQL数字号码;
如:show profile cpu, block io for query 3;
上面详细列出了一条查询语句通过的全部的过程。
参数备注:
ALL 显示全部的开销信息
BLOCK IO 显示块IO相关开销
CONTEXT SWITCHES 上下文切换相关开销
CPU 显示CPU相关开销信息
IPC 显示发送和接收相关开销信息
MEMORY 显示内存相关开销信息
PAGE FAULTS 显示页面错误相关开销信息
SOURCE 显示和Source_function,Source_file,Source_line相关的开销信息
SWAPS 显示交换次数相关开销信息
converting HEAP to MyISAM
:查询结果太大,内存都不够用了往磁盘上搬了create tmp table
:建立临时表,拷贝数据到临时表,用完再删除copying to tmp table on disk
:把内存中临时表复制到磁盘,危险!!!locked