使用explain查询SQL的执行计划:
EXPLAIN EXTENDED SELECT
将执行计划"反编译"成 SELECT 语句,运行 SHOW WARNINGS ,可得到被 MySQL优化器优化后的查询语句。
EXPLAIN PARTITIONS SELECT
用于分区表的 EXPLAIN 生成 QEP 的信息,用来查看索引是否正在被使用,并且输出 其使用的索引的信息。
EXPLAIN SELECT经常使用的方式,查看 sql 的执行计划
explain返回各列的含义
Id 查询中执行select 子句或操作表的顺序,id 值越大优先级越高,越先被执行。
Select_type 所使用的 SELECT 查询类型,包括以下常见类型: SIMPLE、 PRIMARY、SUBQUERY、UNION、DERIVED、UNION RESULT、DEPENDENT、 UNCACHEABLE
table 所使用的的数据表的名字
type 表示 MySQL 在表中找到所需行的方式,又称“访问类型”。取值按优劣排序 为 NULL>system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL ,一般来说,得保证查询至 少达到 range 级别,最好能达到 ref。
Possible_keys 可能使用哪个索引在表中找到记录
key 实际使用的索引
Key_len 索引中使用的字节数
ref 显示索引的哪一列被使用了
rows 估算的找到所需的记录所需要读取的行数
filtered 通过条件过滤出的行数的百分比估计值
extra 包含不适合在其他列中显示但十分重要的额外信息
Using filesort:看到这个的时候,查询就需要优化了。MYSQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行。
Using temporary:看到这个的时候,查询需要优化了。这里,MYSQL徐哟创建一个临时表来存储接口,这通常发生在对不同的列表进行ORDER BY上,而不是GROUP BY上。
Count()和Max()的优化:
explain select max(payment_date) from payment;
建立索引,进行优化:
create index inx_paydate on payment(payment_date);
Count(*)会记录全部行数
Count(某一列)不会记录字段为null的。
-- 在一条SQL中同时查出2006和2007年电影的数量-优化count()函数
如果是2006年计数否则返回null不计数,利用count的特性。
SELECT COUNT(release_year='2006' OR NULL) AS '2006年电影数量',
COUNT(release_year='2007' OR NULL) AS '2007年电影数量'
FROM film;
子查询的优化
通常情况下,需要把子查询优化为join查询,但在优化时需要注意关联键是否有一对多的关系,因为此时要注意会有重复数据,可以用distinct去重。(join查询不需要内建临时表)
group by、order by的优化
group by 后边的字段要用同一个表中的字段。有时候联合查询会出现文件排序,临时表的现象,这时候可以尝试改成子查询的方式灵活运用。
order by 后边字段用主键或索引列。
-- 优化前
SELECT actor.first_name,actor.last_name,COUNT(*)
FROM sakila.film_actor
INNER JOIN film_actor USING(actor_id)
GROUP BY film_actor.actor_id;
-- 优化后
SELECT actor.first_name,actor.last_name,c
FROM sakila.actor INNER JOIN(
SELECT actor_id,COUNT(*) AS cnt FROM sakila.film_actor GROUP BY
actor_id
)AS c USING(actor_id);
索引
在where从句,group by从句,order by从句,on从句中出现的列
索引字段越小越好
离散度大的列放到联合索引的前面(离散度大就是不同的值比较多)。
-- 唯一值越多,离散度越高,可选择性越高。
select count(distinct customer_id),count(distinct staff_id) from payment;
查找重复及冗余索引
需要切换到information_schema数据库执行:(不太好用)
select
a.TABLE_SCHEMA AS '数据名',
a.TABLE_NAME AS '表名',
a.INDEX_NAME AS '索引1',
b.INDEX_NAME AS '索引2',
a.COLUMN_NAME as '重复列名'
from STATISTICS a JOIN STATISTICS b ON
a.TABLE_SCHEMA = b.TABLE_SCHEMA
AND a.TABLE_NAME = b.TABLE_NAME
AND a.SEQ_IN_INDEX = b.SEQ_IN_INDEX
AND a.COLUMN_NAME = b.COLUMN_NAME
使用pt-duplicate-key-checker工具检查重复及冗余索引比较方便可以给出删除的冗余索引。
-- 使用示例
pt-duplicate-key-checker -uroot -p '123321' -h 127.0.0.1
删除不用索引:
目前MySQL中还没有记录索引的使用情况,但是在PerconMySQL和MariaDB中可以通过INDEX_STATISTICS表来查看那些索引未使用,但是MySQL中目前只能通过慢查日志配合pt-index-usage工具来进行索引使用情况的分析。
-- 使用语法
pt-index-usage
-uroot 'passwd'
mysql-slow.log
数据库结构优化
数据类型的选择:
使用可以存下你的数据的最小的数据类型
使用简单的数据类型,Int要比varchar类型在MySQL处理上简单
尽可能的使用not null 定义字段
尽量少用text类型,非要不可时最好考虑分表
1、用int类型存储日期,要使用from_unixtime()将int类型转换为日期,使用unix_timestamp()日期转换为int。
CREATE TABLE test(id INT AUTO_INCREMENT NOT NULL, timestr INT, PRIMARY KEY(id));
INSERT INTO test(timestr) VALUES(UNIX_TIMESTAMP('2014-06-01 13:12:00'));
SELECT FROM_UNIXTIME(timestr) FROM test;
2、使用bigint来存储IP地址(一般的想法是利用varchar来进行存储),利用INET_ATON(),INET_NTOA()两个函数来进行转换,inet_aton将IP地址转为bigint,inet_aton将bigint转换为IP地址。
CREATE TABLE sessions(id INT AUTO_INCREMENT NOT NULL,ipaddress BIGINT,PRIMARY KEY(id));
INSERT INTO sessions(ipaddress) VALUES(INET_ATON('192.168.0.1'));
SELECT INET_NTOA(ipaddress) FROM sessions;
数据库表的反范式优化:
反范式化是指为了查询效率的考虑把原本符合第三范式的表适当的增加冗余,已达到优化查询的目的,反范式化是一种以空间来换取时间的操作。
针对反范式化插入更新删除异常时,我们可以使用外键,虽然外键会影响效率。但是可以有效防止数据出现异常。
数据库表的垂直拆分:
垂直拆分的其中一个重要原因时innodb表每行大小不能超过innodb_page_size。用可变大小的类型,容易超过上限,造成写入数据库不成功。
表的垂直拆分:
所谓的垂直拆分,就是把原理一个有很多列的表拆分成多个表,这解决了表的宽度问题。通常垂直拆分可以按以下原则进行:
1.把不常用的字段单独存放到一个表中。
2.把大字段独立存放到一个表中。
3.把经常一起使用的字段放到一起。
数据库表的水平拆分:
表的水平拆使为了解决单表的数据量过大的问题,水平拆分的表每一个表的结构都是完全一致的。例如电商的销售记录,可以按年(销售记录多的话按年加月)水平拆分,这样也方便统计。
常用的水平拆分方法为:
1.对customer_id进行hash运算,如果要拆分成5个表则使用mod(customer_id,5)取出0-4个值。
2.针对不同的hashID把数据存到不同的表中。
后半部分可以参考一下https://blog.csdn.net/u014465934/article/details/80591316