Explain命令在解决数据库性能上是第一推荐使用命令,大部分的性能问题可以通过此命令来简单的解决,Explain可以用来查看 SQL 语句的执行效 果
id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
---|
1、id:这是SELECT的查询序列号
2、select_type:select_type就是select的类型,可以有以下几种:
SIMPLE:简单SELECT(不使用UNION或子查询等)
PRIMARY:最外面的SELECT
UNION:UNION中的第二个或后面的SELECT语句
DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询
UNION RESULT:UNION的结果。
SUBQUERY:子查询中的第一个SELECT
DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询
DERIVED:导出表的SELECT(FROM子句的子查询)
3、table:显示这一行的数据是关于哪张表的
4、type:这列最重要,显示了连接使用了哪种类别,有无使用索引,是使用Explain命令分析性能瓶颈的关键项之一。
结果值从好到坏依次是:
system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL
一般来说,得保证查询至少达到range级别,最好能达到ref,否则就可能会出现性能问题。
5、possible_keys:列指出MySQL能使用哪个索引在该表中找到行
6、key:显示MySQL实际决定使用的键(索引)。如果没有选择索引,键是NULL
7、key_len:显示MySQL决定使用的键长度。如果键是NULL,则长度为NULL。使用的索引的长度。在不损失精确性的情况下,长度越短越好
8、ref:显示使用哪个列或常数与key一起从表中选择行。
9、rows:显示MySQL认为它执行查询时必须检查的行数。
10、Extra:包含MySQL解决查询的详细信息,也是关键参考项之一。
Distinct
一旦MYSQL找到了与行相联合匹配的行,就不再搜索了
Not exists
MYSQL 优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,
就不再搜索了
Range checked for each
Record(index map:#)
没有找到理想的索引,因此对于从前面表中来的每一 个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一
Using filesort
看 到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来 排序全部行
Using index
列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表 的全部的请求列都是同一个索引的部分的时候
Using temporary
看到这个的时候,查询需要优化了。这 里,MYSQL需要创建一个临时表来存储结果,这通常发生在对不同的列集进行ORDER BY上,而不是GROUP BY上
Using where
使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index, 这就会发生,或者是查询有问题
其他一些Tip:
当type 显示为 “index” 时,并且Extra显示为“Using Index”, 表明使用了覆盖索引。
not in和in
in可以包含null
not in不能包含null
in 判断时,每条记录与集合里的每一个记录比较,只要有一条记录比较相同,就返回true。所以,即使这个集合里有null,也不影响in的结果。
但not in就不一样了,not in要与集合中每条记录比较,每条记录都不相同才返回true。当集合中包含null时,每条记录与之比较都会退出,所以返回的集合也必定为null
因此,not in 判断的集合不能包含null,而in判断的集合可以包括null
想获取null值需要 is null or ...
is not null, not in, not exist
1.select * from A where A.a not in (select a from B)
2.select * from A where not exists (select 1 from B where A.a = B.a)
3.select * from A left join B on A.a = B.a where B.a is null
三者效果一致 尽量避免3,左大使用in或not in(做好is n)
子查询表大的用exists,子查询表小的用in
in是把外表和内表作hash(字典集合)连接,而exists是对外表作循环,每次循环再对内表进行查询
所以exists使用内表的索引,in使用外表的索引
not exists和not in 5.5以上都能使用索引但是not in不能用于null
使用not in(它会调用子查询),而使用not exists(它会调用关联子查询)。如果子查询中返回的任意一条记录含有空值,则查询将不返回任何记录。如果子查询字段有非空限制(即子查询结尾加is not null),这时可以使用not in
如果查询语句使用了not in,那么对内外表都进行全表扫描,没有用到索引;而not exists的子查询依然能用到表上的索引。所以无论哪个表大,用not exists都比not in 要快
注意:mysql5.5 以上 not in != 都可以使用范围索引
exists
exists用于检查子查询返回的结果集是否为空,该子查询实际上并不返回任何数据,而是返回值true或false。
语法: exists subQuery
参数: subQuery 是一个受限的 select 语句 (不允许有 compute 子句和 into 关键字)。
结果类型: boolean 如果子查询包含行,则返回 true ,否则返回 false 。
结论:select * from A where exists (select 1 from B where A.id=B.id);
一种通俗的可以理解为:将外查询表的每一行,代入内查询作为检验,如果内查询返回的结果集非空,则exists子句返回true,这一行方可作为外查询的结果行,否则不能作为结果。
1.避免重复插入
insert into A (column, column2) select column, column2 from B where not exists (select 1 from A where A.column=B.column); # 对column进行去重插入,通过临时表B批量插入数据
单行插入:
insert into A (column, column2) select value, value2 from dual where not exists (select 1 from A where A.column=value);
使用 dual 做表名可以让你在 select 语句后面直接跟上要插入字段的值,即使这些值还不存在当前表中
insert into category_publish_content (category_id, publish_content_uuid)
select 1111, "1111"
from dual
where not exists
(select 1
from category_publish_content
where category_publish_content.category_id=1111
and category_publish_content.publish_content_uuid = "1111");
mysql备份:mysqldump
备份指定数据库所有数据
mysqldump -t -uroot -p -h 数据库名> xxx.sql
备份指定数据库所有表结构
mysqldump -d -uroot -p -h 数据库名> xxx.sql
备份指定数据库所有表结构和数据
mysqldump -uroot -p -h 数据库名> xxx.sql
-u 用户名 -p密码 -h远程主机名
导出多个数据库的信息
mysqldump -uroot -proot -h --databases db1 db2 > xxx.sql
导出指定数据库的指定表
mysqldump -h -uroot -proot database table > xxx.sql
数据库迁移 跨主机
mysqldump --host=host1 --opt 源数据库| mysql --host=host2 -C
# mysql 8.0 默认开启了优化器的导出column-statistics选项
# 增加 --column-statistics=0 使用mysql8.0客户端导出就不会报错了
# 导出例子
mysqldump -uroot -h10.16.0.11 -P3306 -p --column-statistics=0 --set-gtid-purged=OFF --single-transaction --master-data=2 --routines --triggers --events --flush-logs --flush-privileges --databases db0 db1 db2 db3 db4 db5 db6 > login_db10_`date +%Y%m%d_%H%M%S`.sql
mysql:
update label set name = substring(name, 1,(char_length(name)-1))
where right(name,1)='#'