SIMPLE: 简单select查询,查询中不包含子查询或者UNIONPRIMARY: 查询中若包含任何复杂的子查询,最外层查询则被标记为primary.UNION: 若第二个select出现的union之后,则被标记为union;若union包含在from子句的子查询中,外层select将被标记为deriverDEPENDENT UNION: UNION 中的第二个或后面的 SELECT 语句,取决于外面的查询UNION RESULT: 从union表获取结果select,两个UNION合并的结果集在最后SUBQUERY: 在select或where中包含了子查询.DEPENDENT SUBQUERY: 子查询中的第一个 SELECT,取决于外面的查询DERIVED: 在from列表中包含的子查询被标记为derived(衍生),把结果放在临时表当中NULL: MySQL不访问任何表,索引,直接返回结果system: 表仅有一行(=系统表)。这是 const 联接类型的一个特例。const: 表最多有一个匹配行,const用于比较primary 或者 unique索引。直接查询主键或者唯一索引,它将在查询开始时被读取。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const 表很快,因为它们只读取一次!eq_ref: 唯一性索引扫描。对于每个索引键,表中只有一条记录与之匹配。常见于主键或唯一索引扫描,对于每个来自于前面的表的行组合, 从该表中读取一行。这可能是最好的联接类型, 除了 const 类型。ref: 非唯一性索引扫描。对于每个来自于前面的表的行组合, 所有有匹配索引值的行将从这张表中读取。ref_or_null: 该联接类型如同 ref,但是添加了 MySQL 可以专门搜索包含 NULL 值的行。index_merge: 该联接类型表示使用了索引合并优化方法。unique_subquery: 该类型替换了下面形式的 IN 子查询的 ref: value IN (SELECT primary_key FROM single_table WHERE some_expr) unique_subquery 是一个索引查找函数, 可以完全替换子查询, 效率更高。index_subquery: 该联接类型类似于 unique_subquery。可以替换 IN 子查询, 但只适合下列形式的子查询中的非唯一索引: value IN (SELECT key_column FROM single_table WHERE some_expr)range: 只检索给定范围的行,使用一个索引来选择行。index: 该联接类型与 ALL 相同,除了只有索引树被扫描。这通常比 ALL 快,因为索引文件通常比数据文件小。ALL: 对于每个来自于先前的表的行组合, 进行完整的表扫描。性能从最优到最差
要求:一般来说,保证查询至少达到range级别,最好能达到ref
possible_keys与key关系 :理论应该用到哪些索引,实际用到了哪些索引;覆盖索引 查询的字段和建立的字段刚好吻合,这种我们称为覆盖索引。通过查询条件获取的最终记录行数占通过type字段指明的搜索方式搜索出来的记录行数的百分比。filtered列的值依赖统计信息,并不十分准确。Distinct: MySQL 发现第 1 个匹配行后,停止为当前的行组合搜索更多的行。Not exists: MySQL 能够对查询进行 LEFT JOIN 优化, 发现 1 个匹配 LEFT JOIN 标准的行后, 不再为前面的的行组合在该表内检查更多的行。range checked for each record (index map: #): MySQL 没有发现好的可以使用的索引, 但发现如果来自前面的表的列值已知, 可能部分索引可以使用。Using filesort: MySQL 需要额外的一次传递, 以找出如何按排序顺序检索行。所有不是通过索引直接返回排序结果的排序Using index: 使用覆盖索引的时候就会出现 ,只使用索引树中的信息而不需要进一步搜索读取实际的行来检索表中的列信息。Using temporary: 为了解决查询, MySQL 需要创建一个临时表来容纳结果。Using where: 在查找使用索引的情况下,需要回表去查询所需的数据 。Using sort_union(...), Using union(...), Using intersect(...): 这些函数说明如何为 index_merge 联接类型合并索引扫描。Using index for group-by: 类似于访问表的 Using index 方式,Using index for group-by 表示 MySQL 发现了一个索引,可以用来查询using index condition:查找使用了索引,但是需要回表查询数据using index ; using where:查找使用了索引,但是需要的数据都在索引列中能找到,所以不需要回表 查询数据小表驱动大表 原则符合条件的表的行数 * 每行的大小。参与 join 的各个字段的总数据量,数据量小的那个表,就是“小表”,应该作为驱动表驱动表,右边的表称为被驱动表,我们要在被驱动表上加索引。
示例
explain select s.sku_code,s.product_name,s.average_amount,si.amount
from sku_inventory as si
left join sku as s
on s.sku_code = si.sku_code

explain select s.sku_code,s.product_name,s.average_amount,si.amount
from sku as s
left join sku_inventory as si
on s.sku_code = si.sku_code

# index(section_code,shelf_code)
#索引起作用了
explain select section_code,shelf_code from location where shelf_code='E1-01-28%'

explain select s.product_name
from sku as s where s.sku_code like '%78504772808'

explain select s.product_name
from sku as s where s.sku_code like '78504772808%'

explain select s.product_name
from sku as s where s.sku_code='78504772808'

explain select * from location where code like 'A%'

explain select code from location where code like 'A%'

explain select * from sku where sku_code='78166804828' or sku_code='78464859935'

explain select * from sku where sku_code in ('78166804828','78464859935')

explain select * from sku where sku_code='78166804828'
union
select * from sku where sku_code='78464859935'

# OR前后存在非索引的列,索引失效
explain select * from sku where sku_code='78166804828' or sku.product_name='耳机'

# 只有 warehouse_code 起作用
explain select * from location where warehouse_code='FJI' and shelf_code='A-01-01'

# 都没起作用
explain select * from location where warehouse_code='FJI' or section_code='A'

返回表中30%内的数据会走索引,返回超过30%数据就使用全表扫描。当然这个结论太绝对了,也并不是绝对的30%,只是一个大概的范围。
# warehouse_code,section_code 起了作用
explain select * from location where warehouse_code='FJI' and section_code='A' and shelf_code='A-01-01'

# 不起作用
explain select * from location where section_code='A' and aisle_code='01'

explain select * from goods_purchase_order where code=10148131

explain select * from goods_purchase_order where code='10148131'

回表:当对一个列创建索引之后,索引会包含该列的键值及键值对应行所在的rowid。通过索引中记录的rowid访问表中的数据就叫回表。回表次数太多会严重影响SQL性能,如果回表次数太多,就不应该走索引扫描,应该直接走全表扫描。
explain select section_code,shelf_code from location where section_code='E1' or shelf_code='E1-01-28'

explain select * from location where section_code='E1' or shelf_code='E1-01-28'

Using index condition,就是指使用到了索引下推。# index(warehouse_code, section_code, aisle_code, shelf_code, code)
explain select * from location where warehouse_code='FJI' and shelf_code='A-01-01'

warehouse_code='FJI' 使用上了索引,但是后面由于最左前缀匹配原则,所以shelf_code无法使用上索引,但是存储引擎此时会进行一种优化:索引下推。也就是通过索引查询出数据后,并不急着回表,而是先通过后面的shelf_code查询过滤掉不符合的数据,最后再回表查询所有的列数据,这就叫做索引下推。shelf_code='A-01-01' 的条件,这样增多了回表的次数。# index(code)
explain select * from location where substring(code,8)='A-01-01'

explain select * from t_user where id in (select user_id from user_role );
explain select * from t_user u , user_role ur where u.id = ur.user_id;
explain select * from t_user u left join user_role ur on u.id = ur.user_id;
编写顺序
SELECT DISTINCT
<select list>
FROM
<left_table> <join_type>
JOIN
<right_table> ON <join_condition>
WHERE
<where_condition>
GROUP BY
<group_by_list>
HAVING
<having_condition>
ORDER BY
<order_by_condition>
LIMIT
<limit_params>
执行顺序
FROM
<left_table>
ON <join_condition>
<join_type> JOIN <right_table>
WHERE <where_condition>
GROUP BY <group_by_list>
HAVING <having_condition>
SELECT DISTINCT <select list>
ORDER BY <order_by_condition>
LIMIT <limit_params>
你知道的越多,你不知道的越多。