【发布时间】:2011-12-07 12:57:54
【问题描述】:
几乎在我读到的所有地方都非常不鼓励使用FORCE INDEX,我完全理解并知道为什么——MySQL 比(普通)开发人员更清楚要选择哪些索引的可能性非常大。
然而,最近我发现了一个案例,FORCE INDEX 将我的执行时间提高了数百倍:
-
JOIN4 张桌子 - 第一个表有大约 500 000 条记录
-
INNER JOINed 表中有 2 条记录超过 100 万条 - 第一个表有一个名为
published_date的字段,以YMD格式存储为varchar(无法更改为datetime) - 需要
published_date的范围内最多 5 000 条记录 - 此查询需要第一个表上的其他一些
GROUP BY和ORDER BY子句与published_date不同的字段
虽然我以多种方式重写了查询,但我无法获得小于 130 秒的执行时间(最高超过 700 秒)。将FORCE INDEX 与published_date 一起使用后,执行时间降至5 秒以下。
我花了几天时间才想起臭名昭著的 FORCE INDEX 选项。
问题:
- 您发现
FORCE INDEX拯救了您的其他用例还有哪些? - 您在考虑使用
FORCE INDEX时是否有一些最佳做法?
编辑 - 观察: 我在这里也用这个问题创建了this blog post。您提供的所有答案也会出现在那里 - 包括学分和您想要的所有东西。
编辑 2
我应用了我在您的 cmets 中收到的建议(ANALYZE TABLE 和 OPTIMIZE TABLE),下面是在查询中应用的 EXPLAIN 的输出 - 不幸的是,索引选择并没有更好:
1. 没有FORCE INDEX 别名a:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE am2 range PRIMARY,idx_meta_article idx_meta_article 4 NULL 275228 Using where; Using index; Using temporary; Using f...
1 SIMPLE a eq_ref PRIMARY,serial_issue_date_productid,pub_date,idx_d... PRIMARY 4 mydb_toto.am2.ArticleID 1 Using where
1 SIMPLE ai ref PRIMARY,idx_iso_article PRIMARY 4 mydb_toto.a.serial 11523 Using where; Using index
1 SIMPLE m range PRIMARY,meta_articles_type meta_articles_type 4 NULL 96 Using where
1 SIMPLE am eq_ref PRIMARY,idx_meta_article PRIMARY 8 mydb_toto.a.serial,mydb_toto.m.meta_id 1 Using where; Using index
2. FORCE INDEX 在桌子上,别名 a:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE a range pub_date pub_date 11 NULL 17679 Using where; Using temporary; Using filesort
1 SIMPLE am2 ref PRIMARY,idx_meta_article PRIMARY 4 mydb_toto.a.serial 21930 Using where; Using index
1 SIMPLE ai ref PRIMARY,idx_iso_article PRIMARY 4 mydb_toto.a.serial 11523 Using where; Using index
1 SIMPLE m range PRIMARY,meta_articles_type meta_articles_type 4 NULL 96 Using where
1 SIMPLE am eq_ref PRIMARY,idx_meta_article PRIMARY 8 mydb_toto.am2.ArticleID,mydb_toto.m.meta_id 1 Using where; Using index
3. 在ANALYZE TABLE之后,没有FORCE INDEX:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE am2 range PRIMARY,idx_meta_article idx_meta_article 4 NULL 275228 Using where; Using index; Using temporary; Using f...
1 SIMPLE a eq_ref PRIMARY,serial_issue_date_productid,pub_date,idx_d... PRIMARY 4 mydb_toto.am2.ArticleID 1 Using where
1 SIMPLE ai ref PRIMARY,idx_iso_article PRIMARY 4 mydb_toto.a.serial 11523 Using where; Using index
1 SIMPLE m range PRIMARY,meta_articles_type meta_articles_type 4 NULL 96 Using where
1 SIMPLE am eq_ref PRIMARY,idx_meta_article PRIMARY 8 mydb_toto.a.serial,mydb_toto.m.meta_id 1 Using where; Using index
4. 在OPTIMIZE TABLE之后,没有FORCE INDEX:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE am2 range PRIMARY,idx_meta_article idx_meta_article 4 NULL 275228 Using where; Using index; Using temporary; Using f...
1 SIMPLE a eq_ref PRIMARY,serial_issue_date_productid,pub_date,idx_d... PRIMARY 4 mydb_toto.am2.ArticleID 1 Using where
1 SIMPLE ai ref PRIMARY,idx_iso_article PRIMARY 4 mydb_toto.a.serial 11523 Using where; Using index
1 SIMPLE m range PRIMARY,meta_articles_type meta_articles_type 4 NULL 96 Using where
1 SIMPLE am eq_ref PRIMARY,idx_meta_article PRIMARY 8 mydb_toto.a.serial,mydb_toto.m.meta_id 1 Using where; Using index
5. 在OPTIMIZE TABLE 和ANALYZE TABLE 之后,加上FORCE INDEX:
id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE a range pub_date pub_date 11 NULL 17679 Using where; Using temporary; Using filesort
1 SIMPLE am2 ref PRIMARY,idx_meta_article PRIMARY 4 mydb_toto.a.serial 21930 Using where; Using index
1 SIMPLE ai ref PRIMARY,idx_iso_article PRIMARY 4 mydb_toto.a.serial 11523 Using where; Using index
1 SIMPLE m range PRIMARY,meta_articles_type meta_articles_type 4 NULL 96 Using where
1 SIMPLE am eq_ref PRIMARY,idx_meta_article PRIMARY 8 mydb_toto.am2.ArticleID,mydb_toto.m.meta_id 1 Using where; Using index
【问题讨论】:
-
您是否在必须
FORCE INDEX的表上运行了ANALYZE TABLE? -
我的经验还告诉我,您需要指示规划器使用某个索引的情况非常少见,大多数情况下它选择不佳是因为索引损坏或错误,这将通过 ANALYZE 修复.
-
@Romain - 没有分析表运行...好主意
-
@TudorConstantin 您可以尝试分析它们,然后将新的“香草”查询计划与“强制”查询计划进行比较......也许在此之后它们会相同。
-
强制使用特定索引的问题在于,即使今天取得了更好的性能,也无法轻易预测修改表统计信息的后果,尤其是对于复杂的查询。查询优化器几乎总是选择最佳执行计划,并且还可以适应变化。除了使用 ANALYZE 来更新表统计信息之外,如果您正在进行大量修改(大量的 DELETE/INSERT)也可以对索引页进行排序,您还可以使用 OPTIMIZE dev.mysql.com/doc/refman/5.1/en/optimize-table.html。
标签: mysql