分析查询效率应该依赖explain命令吗?
Should rely on explain command when analyzing query efficiency?
explain SELECT * FROM house JOIN street s on house.STREET_ID = s.ID WHERE s.type<>'out_of' AND street.DISTRICT_ID=4 ORDER BY house.num;
explain SELECT * FROM house JOIN street s on house.STREET_ID = s.ID WHERE s.type<>'out_of' AND house.DISTRICT_ID=4 ORDER BY house.num;
Type 和 district_id 是在 Street table 中编入索引的化合物
district_id 在众议院 table
中编入索引
- 说明与street.DISTRICT_ID=4,街道table相连
<data>
<row>
<id>1</id>
<select_type>SIMPLE</select_type>
<table>street</table>
<type>ref</type>
<possible_keys>PRIMARY,FK_STREET_DISTRICT,IDX_STREET_DISTRICT_ID_STREET_TYPE</possible_keys>
<key>IDX_STREET_DISTRICT_ID_STREET_TYPE</key>
<key_len>8</key_len>
<ref>const</ref>
<rows>16</rows>
<Extra>Using index condition; Using temporary; Using filesort</Extra>
</row>
<row>
<id>1</id>
<select_type>SIMPLE</select_type>
<table>house</table>
<type>ref</type>
<possible_keys>FK_HO_ST,idx_or_st_entity</possible_keys>
<key>FK_HO_ST</key>
<key_len>8</key_len>
<ref>street.ID</ref>
<rows>70695</rows>
<Extra></Extra>
</row>
</data>
- 用house.DISTRICT_ID=4
解释
<data>
<row>
<id>1</id>
<select_type>SIMPLE</select_type>
<table>house</table>
<type>ALL</type>
<possible_keys>FK_ST_HO,FK_ST_DISTRICT,idx_or_st_entity,IDX_HO_DISTRICT_NUM</possible_keys>
<key>null</key>
<key_len>null</key_len>
<ref>null</ref>
<rows>989734</rows>
<Extra>Using where; Using filesort</Extra>
</row>
<row>
<id>1</id>
<select_type>SIMPLE</select_type>
<table>street</table>
<type>eq_ref</type>
<possible_keys>PRIMARY</possible_keys>
<key>PRIMARY</key>
<key_len>8</key_len>
<ref>house.STREET_ID</ref>
<rows>1</rows>
<Extra>Using where</Extra>
</row>
</data>
DISTRICT_ID 对于 house 和 street 是相同的,但是接收到的估计行有很大的不同。这是否意味着使用连接 DISTRICT_ID 的查询效率更高,估计行数 = 70695?
第一个查询实际上正在检查估计的 1,131,120 行。对于 JOIN 查询,您应该查看联接的 table 之间的 rows
字段的乘积。在您的情况下,它估计它将检查 street
中的 16 行,并且对于这些行中的每一行,它估计它将检查连接的 table house
中的 70,695 行。 16*70695 = 1131120.
而第二个 table 估计它将检查 house
中的 989,734 行(作为 table-scan,由 type: ALL
表示),以及每个匹配的行, 它将通过主键(由 type: eq_ref
表示)在连接的 table street
中查找 1 行。
对数字持保留态度。它们只是估计值,可能会相差很多。最好不要将它们视为精确的数字,而应视为数量级。我会认为它们都是低效的,除非你期望查询的最终结果有数十万行。
没有看到您的 table,很难猜出更好的索引策略。通常关于 query-optimization 的问题应该包括 link 到 dbfiddle,或者查询中每个 table 的 SHOW CREATE TABLE
的输出。
根据您的查询,我猜 table 都有一个 DISTRICT_ID
列。这是多余的,还是可以用来优化连接条件?例如:
...
FROM house h JOIN street s
ON h.STREET_ID = s.ID AND h.DISTRICT_ID = s.DISTRICT_ID
...
我的想法是,如果这可以用来缩小检查的行数,那么将它添加到索引中是值得的。但鉴于您提供的关于这些 table 的有限信息,我无法确定。
explain SELECT * FROM house JOIN street s on house.STREET_ID = s.ID WHERE s.type<>'out_of' AND street.DISTRICT_ID=4 ORDER BY house.num;
explain SELECT * FROM house JOIN street s on house.STREET_ID = s.ID WHERE s.type<>'out_of' AND house.DISTRICT_ID=4 ORDER BY house.num;
Type 和 district_id 是在 Street table 中编入索引的化合物 district_id 在众议院 table
中编入索引- 说明与street.DISTRICT_ID=4,街道table相连
<data>
<row>
<id>1</id>
<select_type>SIMPLE</select_type>
<table>street</table>
<type>ref</type>
<possible_keys>PRIMARY,FK_STREET_DISTRICT,IDX_STREET_DISTRICT_ID_STREET_TYPE</possible_keys>
<key>IDX_STREET_DISTRICT_ID_STREET_TYPE</key>
<key_len>8</key_len>
<ref>const</ref>
<rows>16</rows>
<Extra>Using index condition; Using temporary; Using filesort</Extra>
</row>
<row>
<id>1</id>
<select_type>SIMPLE</select_type>
<table>house</table>
<type>ref</type>
<possible_keys>FK_HO_ST,idx_or_st_entity</possible_keys>
<key>FK_HO_ST</key>
<key_len>8</key_len>
<ref>street.ID</ref>
<rows>70695</rows>
<Extra></Extra>
</row>
</data>
- 用house.DISTRICT_ID=4 解释
<data>
<row>
<id>1</id>
<select_type>SIMPLE</select_type>
<table>house</table>
<type>ALL</type>
<possible_keys>FK_ST_HO,FK_ST_DISTRICT,idx_or_st_entity,IDX_HO_DISTRICT_NUM</possible_keys>
<key>null</key>
<key_len>null</key_len>
<ref>null</ref>
<rows>989734</rows>
<Extra>Using where; Using filesort</Extra>
</row>
<row>
<id>1</id>
<select_type>SIMPLE</select_type>
<table>street</table>
<type>eq_ref</type>
<possible_keys>PRIMARY</possible_keys>
<key>PRIMARY</key>
<key_len>8</key_len>
<ref>house.STREET_ID</ref>
<rows>1</rows>
<Extra>Using where</Extra>
</row>
</data>
DISTRICT_ID 对于 house 和 street 是相同的,但是接收到的估计行有很大的不同。这是否意味着使用连接 DISTRICT_ID 的查询效率更高,估计行数 = 70695?
第一个查询实际上正在检查估计的 1,131,120 行。对于 JOIN 查询,您应该查看联接的 table 之间的 rows
字段的乘积。在您的情况下,它估计它将检查 street
中的 16 行,并且对于这些行中的每一行,它估计它将检查连接的 table house
中的 70,695 行。 16*70695 = 1131120.
而第二个 table 估计它将检查 house
中的 989,734 行(作为 table-scan,由 type: ALL
表示),以及每个匹配的行, 它将通过主键(由 type: eq_ref
表示)在连接的 table street
中查找 1 行。
对数字持保留态度。它们只是估计值,可能会相差很多。最好不要将它们视为精确的数字,而应视为数量级。我会认为它们都是低效的,除非你期望查询的最终结果有数十万行。
没有看到您的 table,很难猜出更好的索引策略。通常关于 query-optimization 的问题应该包括 link 到 dbfiddle,或者查询中每个 table 的 SHOW CREATE TABLE
的输出。
根据您的查询,我猜 table 都有一个 DISTRICT_ID
列。这是多余的,还是可以用来优化连接条件?例如:
...
FROM house h JOIN street s
ON h.STREET_ID = s.ID AND h.DISTRICT_ID = s.DISTRICT_ID
...
我的想法是,如果这可以用来缩小检查的行数,那么将它添加到索引中是值得的。但鉴于您提供的关于这些 table 的有限信息,我无法确定。