explain主要用于sql语句中的select查询,可以显示的查看该sql语句索引的命中情况,从而更好的利用索引、优化查询效率。
Explain语法如下:explain [extended] select ...
其中extended是选用的,如果使用的extended,那么explain之后就可以使用show warnings查看相应的优化信息,也就是mysql内部实际执行的query。
列名 |
描述 |
说明 |
相关链接 |
id |
若没有子查询和联合查询,id则都是1。 |
Mysql会按照id从大到小的顺序执行query,在id相同的情况下,则从上到下执行。 |
|
select_type |
select类型。 |
常见类型 |
|
table |
输出的行所引用的表。 |
有时看到的是 |
|
type |
Mysql的存取方法,连接访问类型。 |
常见类型 |
|
possible_keys |
在查询过程中可能用到的索引。 |
在优化初期创建该列,但在以后的优化过程中会根据实际情况进行选择,所以在该列列出的索引在后续过程中可能没用。该列为NULL意味着没有相关索引,可以根据实际情况看是否需要加索引。 |
|
key |
访问过程中实际用到的索引。 |
有可能不会出现在possible_keys中(这时可能用的是覆盖索引,即使query中没有where)。possible_keys揭示哪个索引更有效,key是优化器决定哪个索引可能最小化查询成本,查询成本基于系统开销等总和因素,有可能是“执行时间”矛盾。如果强制mysql使用或者忽略possible_keys中的索引,需要在query中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。 |
|
key_len |
显示使用索引的字节数。 |
由根据表结构计算得出,而不是实际数据的字节数。如ColumnA(char(3)) ColumnB(int(11)),在utf-8的字符集下,key_len=3*3+4=13。计算该值时需要考虑字符列对应的字符集,不同字符集对应不同的字节数。 |
mysql5.1.5下latin1、utf8、gbk字符数、字节数、汉字的对应关系 |
ref |
显示了哪些字段或者常量被用来和 |
||
rows |
估计为返回结果集而需要扫描的行。 |
不是最终结果集的函数,把所有的rows乘起来可估算出整个query需要检查的行数。有limit时会不准确。(为毛?) |
|
Extra |
mysql查询的附加信息。 |
常见信息 |
select类型:
simple:query中不包含子查询或联合查询。
primary:包含子查询或联合查询的query中,最外层的select查询。
subquery:子查询在select的目标里,不在from中,子查询的第一个select。
例如:EXPLAIN SELECT (SELECT actor_id FROM actor) FROM film_actor
dependent subquery:子查询内层的第一个select,依赖于外部查询的结果集。
例如:EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM film_actor)
EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM film_actor WHERE actor_id=1)
EXPLAIN SELECT * FROM actor WHERE actor_id = (SELECT actor_id FROM film_actor WHERE actor_id=1)
uncacheable subquery:表示子查询,但返回结果不能被cache,必须依据外层查询重新计算。(在什么情况下会出现这个?)
derived:子查询在from子句中,执行查询的时候会把子查询的结果集放到临时表(衍生表)。
例如:EXPLAIN SELECT * FROM (SELECT * FROM actor) AS a。此时table列会显示
union:在联合查询中第二个及其以后的select对应的类型。
例如:EXPLAIN SELECT * FROM film_actor UNION ALL SELECT * FROM actor
如果union包含在一个from子查询里面,则from子查询中的第一个select标记为derived。
例如:EXPLAIN SELECT * FROM ( SELECT * FROM film_actor UNION ALL SELECT * FROM actor) a
union result:从union临时表获取结果集合。例如上面两个查询结果集中的最后一行。
dependent union:子查询中的union,且为union中第二个select开始的后面所有select,同样依赖于外部查询的结果集。
例如:EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM film_actor UNION ALL SELECT actor_id FROM film_actor)
uncacheable union:表示union第二个或以后的select,但结果不能被cache,必须依据外层查询重新计算。(在什么情况下会出现)
按照效率从高到低给出几种常见的type类型:
NULL:mysql在优化过程中分解query,执行时甚至不用再访问表数据或者索引,比如id=-1。
例如:EXPLAIN SELECT * FROM actor WHERE actor_id = -1
system:查询的表仅有一行。这是const联接类型的一个特例。(在没有任何索引的情况下,只有一条数据,MyISAM会显示system,InnoDB会显示ALL)
const:最多会有一条记录匹配。因为仅有一行,在这行的列值可被优化器剩余部分认为是常数。const表很快,因为它们只读取一次。发生在有一个unique key或者主键,并且where子句给它设定了一个比较值。
例如:EXPLAIN SELECT * FROM actor WHERE actor_id = 1(其中actor_id是主键)
eq_ref:使用这种索引查找,最多返回一条符合条件的记录。会在使用主键或者唯一性索引访问数据时看到,除了const类型这可能是最好的联接类型。
例如:EXPLAIN SELECT * FROM actor, actorsex WHERE actor.actor_id = actorsex.actor_id(其中actor_id是actor、actorsex的主键,且actorsex中只有一条记录,如果多于一条记录就不是eq_ref)
ref:这是一种索引访问。只有当使用一个非唯一性索引或者唯一性索引的非唯一性前缀(换句话说,就是无法根据该值只取得一条记录)时才会发生,将索引和某个值相比较,这个值可能是一个常数,也可能是来自前一个表里的多表查询的结果值。如果使用的键仅仅匹配少量行,该联接类型是不错的。
例如:EXPLAIN SELECT * FROM film_actor,actor WHERE film_actor.actor_id=actor.actor_id AND film_actor.actor_id=1
ref_or_null:类似ref。不同的是Mysql会在检索的时候额外的搜索包含 NULL 值的记录,他意味着mysql必须进行二次查找,在初次查找的结果中找出NULL条目。
index_merge:查询中使用两个或多个索引,然后对索引结果进行合并。在这种情况下,key列包含所有使用的索引,key_len包含这些索引的最长的关键元素。
select * from test where column1 = 1 or column2 = 2(没试出来!555555)
unique_subquery:用来优化有子查询的in,并且该子查询是通过一个unique key选择的。子查询返回的字段组合是主键或者唯一索引。
例如:EXPLAIN SELECT * FROM actor WHERE actor_id IN (SELECT actor_id FROM actor)
index_subquery:该联接类型类似于unique_subquery,子查询中的返回结果字段组合是一个索引或索引组合,但不是一个主键或者唯一索引。
例如:EXPLAIN SELECT * FROM film_actor WHERE film_id IN (SELECT film_id FROM film_actor)
range:在一定范围内扫描索引。如where中带有between或者>,此时ref列为NULL。当使用=、<>、>、>=、<、<=、IS NULL、<=>、BETWEEN或者IN操作符,用常量比较关键字列时,可以使用range。
index:按索引次序扫描数据。因为按照索引扫描所以会避免排序,但也会扫描整表数据,若随机读取开销会更大。如果extra列显示using index,说明使用的是覆盖索引(覆盖索引:包含所有满足查询需要的数据列的索引)。对于InnoDB表特别有用,此时只访问索引数据即可,不用再根据主键信息获取原数据行,避免了二次查询,而MyISAM表优化效果相对InnoDB来说没有那么的明显。
all:按行扫描全表数据,除非查询中有limit或者extra列显示使用了distinct或notexists等限定词。
Extra信息 :
distinct:当mysql找到第一条匹配的结果值时,就停止该值的查询,然后继续该列其他值的查询。
not exists:在左连接中,优化器可以通过改变原有的查询组合而使用的优化方法。当发现一个匹配的行之后,不再为前面的行继续检索,可以部分减少数据访问的次数。例如,表t1、t2,其中t2.id为not null,对于SELECT * FROM t1 LEFT JOIN t2 ON t1.id=t2.id WHERE t2.id IS NULL;由于 t2.id非空,所以只可能是t1中有,而t2中没有,所以其结果相当于求差。left join原本是要两边join,现在Mysql优化只需要依照 t1.id在t2中找到一次t2.id即可跳出。
const row not found:涉及到的表为空表,里面没有数据。
Full scan on NULL key:是优化器对子查询的一种优化方式,无法通过索引访问NULL值的时候会做此优化。
Impossible Having:Having子句总是false而不能选择任何列。例如having 1=0
Impossible WHERE:Where子句总是false而不能选择任何列。例如where 1=0
Impossible WHERE noticed after reading const tables:mysql通过读取“const/system tables”,发现Where子句为false。也就是说:在where子句中false条件对应的表应该是const/system tables。这个并不是mysql通过统计信息做出的,而是真的去实际访问一遍数据后才得出的结论。当对某个表指定了主键或者非空唯一索引上的等值条件,一个query最多只可能命中一个结果,mysql在explain之前会优先根据这一条件查找对应记录,并用记录的实际值替换query中所有用到来自该表属性的地方。
例如:select * from a,b where a.id = 1 and b.name = a.name
执行过程如下:先根据a.id = 1找到一条记录(1, 'name1'),然后将b.name换成'name1',然后通过a.name = 'name1'查找,发现没有命中记录,最终返回“Impossible WHERE noticed after reading const tables”。
No matching min/max row:没有行满足如下的查询条件。
例如:EXPLAIN SELECT MIN(actor_id) FROM actor WHERE actor_id > 3(只有两条记录)
actor_id为唯一性索引时,会显示“No matching min/max row”,否则会显示“using where”。
no matching row in const table:对一个有join的查询,包含一个空表或者没有数据满足一个唯一索引条件。
No tables used:查询没有From子句,或者有一个From Dual(dual:虚拟表,是为了满足select...from...习惯)子句。
例如:EXPLAIN SELECT VERSION()
Range checked for each record (index map: N):Mysql发现没有好的index,但发现如果进一步获取下一张join表的列的值后,某些index可以通过range等使用。Mysql没找到合适的可用的索引。取代的办法是,对于前一个表的每一个行连接,它会做一个检验以决定该使用哪个索引(如果有的话),并且使用这个索引来从表里取得记录。这个过程不会很快,但总比没有任何索引时做表连接来得快。
Select tables optimized away:当我们使用某些聚合函数来访问存在索引的某个字段时,优化器会通过索引直接一次定位到所需要的数据行完成整个查询。在使用某些聚合函数如min, max的query,直接访问存储结构(B树或者B+树)的最左侧叶子节点或者最右侧叶子节点即可,这些可以通过index解决。Select count(*) from table(不包含where等子句),MyISAM保存了记录的总数,可以直接返回结果,而Innodb需要全表扫描。Query中不能有group by操作。
一意の行が見つかりません: SELECT ... FROM tbl_name の場合、一意のインデックスまたは主キーを満たす行がありません。存在しない ID を持つテーブルの値をクエリすると、const テーブルの読み取り後に Impossible WHERE が表示されます。
filesort を使用する: MySQL が結果をインデックス順に並べるのではなく、外部ソートを使用することを意味します。データが少ない場合はメモリから並べ替え、それ以外の場合はディスクから並べ替えます。 Explain は、クライアントにどのソートを使用するかを明示的に指示しません。
インデックスの使用: MySQL がテーブル全体のスキャンを回避するためにカバー インデックスを使用し、テーブル内のデータを 2 回検索する必要がないことを示します。 type のインデックス タイプと混同しないように注意してください。
group-by にインデックスを使用する: インデックスの使用と同様、クエリに group by 句または unique 句があり、group フィールドもインデックスに含まれている場合は、必要なデータをインデックスから読み取るだけで済みます。 extra は値を表示します。
一時的な使用: MySQL は中間結果を収容するための一時テーブルを作成します。必要に応じて、group by および order by で。たとえば、group by が非キー列の場合、オプティマイザは group by 条件に従って構築された一意のキーを持つ一時テーブルを作成し、各クエリ結果に対して (group by を無視して) 一時テーブルへの挿入を試みます。テーブルへの挿入が失敗すると、既存のレコードがそれに応じて更新されます。たとえば、name にインデックスがない場合、SELECT name,COUNT(*) FROM product GROUP BY name でソートするために、Mysql は一時テーブルを作成する必要があります。このとき、通常はファイルソートを使用していると表示されます。
Using where: MySQL がストレージ エンジンによって抽出された結果をフィルタリングすることを示します。たとえば、price にはインデックスがなく、SELECT * FROM product WHERE Price=1300.00 となります。インデックス内の列を含み、検索中にフィルタリングできる where 条件が多数あるため、where 句を含むすべてのクエリで [Using where] が表示されるわけではありません。
結合バッファーの使用: バージョン 5.1.18 以降でのみ使用可能な値。結合の戻り列をバッファから取得して、現在のテーブルと結合できます。
例: select * from t1,t2 where t1.col
スキャンされた N データベース: information_schema クエリを処理するときにスキャンする必要があるディレクトリの数を指します。
例: EXPLAIN SELECT TABLE_NAME, ROW_FORMAT FROM INFORMATION_SCHEMA.TABLES
オンラインでは、このクエリでは「すべてのデータベースをスキャンしました」と表示されると言われています。試してみましたが、追加の列は空でした。
Skip_open_table、Open_frm_only、Open_trigger_only、Open_full_table: information_schema から情報をクエリするときのファイル オープンの最適化を示します。 Skip_open_table: テーブル情報は取得されているため、オープンする必要はありません。 Open_frm_only: .frm ファイルのみを開きます。 Open_trigger_only: .trg ファイルのみを開きます。 Open_full_table: 最適化なし。 .frm、.myd、および .myi ファイルはすべて開かれています。
sort_union(…) の使用、union(…) の使用、intersect(…) の使用: すべて、index_merge 読み取りタイプに表示されます。 sort_union の使用: データを抽出するには 2 つ以上のキーを使用しますが、オプティマイザーは各キーが自然にソートされた結果を抽出することを保証できないため、冗長なデータを削除するには追加の処理が必要です。たとえば、顧客の状態 (lname, fname) はキーですが、SELECT COUNT(*) FROM customer WHERE (lname = 'Jones') OR (state = 'UT') は存在しないため、キーではありません。 lname にキーがあるため、(lname, fname) を使用すると、結果が順序どおりにならない可能性があり、オプティマイザーには追加の作業が必要になります。 Union を使用する: 複数のキーを使用してデータを抽出します。別々に得られた結果をマージすることで、正しい結果が得られます。たとえば、customer の state と (lname, fname) はキーで、SELECT COUNT(state) FROM customer WHERE (lname = 'Jones' AND fname='John') OR (state = 'UT') です。 intersect を使用する: 2 つ以上のキーを使用してデータを抽出し、それぞれ得られた結果をソートし、intersect することで正しい結果を得ることができます。たとえば、customer の state と (lname, fname) はキーで、SELECT COUNT(state) FROM customer WHERE (lname = 'Jones' AND fname='John') AND (state = 'UT') となります。
プッシュされた条件で where を使用する: ndb でのみ使用されます。 Mysql Cluster は、条件プッシュダウン最適化を使用して、インデックスのないフィールドと定数間の直接比較を改善します。条件はクラスターのデータ ノードにプッシュダウンされ、すべてのデータ ノードで同時に評価され、ネットワーク送信を回避するために修飾されていない列が削除されます。
mysql5.1.5 での latin1、utf8、および gbk の文字数、バイト、および漢字の対応関係:
ラテン1:
1character=1byte, 1漢字=2character フィールドは varchar(200) として定義され、100 バイトの漢字または 200 文字を格納できます。特にフィールドの内容が文字や漢字で構成されている場合は、フィールドの内容が漢字で構成されているものとみなしてフィールド長を設定してください。
utf8:
1 文字 = 3 バイト、1 漢字 = 1 文字 フィールドが varchar(200) として定義されている場合、200 文字または 200 文字を格納でき、600 バイトを占有します。
gbk:
1 文字 = 2 バイト、1 漢字 = 1 文字 フィールドが varchar(200) として定義されている場合、200 文字または 200 文字を格納でき、400 バイトを占有します。
Word 版パッケージのダウンロード