Mysql 简单的SQL查询,但庞大的表-如何优化?

Mysql 简单的SQL查询,但庞大的表-如何优化?,mysql,sql,indexing,query-optimization,where-clause,Mysql,Sql,Indexing,Query Optimization,Where Clause,我有一个非常简单的MySQL查询: SELECT target FROM table WHERE goal_id=1 AND year>=2015 AND year<=2020 不过,该表大约有500万行。因此,速度非常慢,大约10秒 我能做些什么来改进?索引是否有帮助?如果有,请选择哪列?对于此查询,您需要以下索引: create index myindex on mytable(year, goal_id, target) 这为您提供了一个覆盖索引:查询中起作用的所有列都是索

我有一个非常简单的MySQL查询:

SELECT target FROM table WHERE goal_id=1 AND year>=2015 AND year<=2020
不过,该表大约有500万行。因此,速度非常慢,大约10秒


我能做些什么来改进?索引是否有帮助?如果有,请选择哪列?

对于此查询,您需要以下索引:

create index myindex on mytable(year, goal_id, target)
这为您提供了一个覆盖索引:查询中起作用的所有列都是索引的一部分,因此这为数据库提供了一个很好的机会,通过只查看索引而不实际查看数据来执行查询

索引中列的顺序很重要:前两列对应where谓词,最后一列是select子句中起作用的列

根据数据的基数,您可能还希望尝试反转前两列:

create index myindex on mytable(goal_id, year, target)

基本思想是,您希望首先放置限制性更强的条件。

对于此查询,您需要以下索引:

create index myindex on mytable(year, goal_id, target)
这为您提供了一个覆盖索引:查询中起作用的所有列都是索引的一部分,因此这为数据库提供了一个很好的机会,通过只查看索引而不实际查看数据来执行查询

索引中列的顺序很重要:前两列对应where谓词,最后一列是select子句中起作用的列

根据数据的基数,您可能还希望尝试反转前两列:

create index myindex on mytable(goal_id, year, target)
基本思想是,你要先制定更严格的标准。

关于年份、目标id和目标的指数:

正如前面所指出的,目标id需要在综合索引中位于第一位,因为它与一个=,然后是您的范围列year,然后是您想要检索的内容,即target。

关于year、goal\u id和target的索引:


如前所述,目标id必须在综合指数中位于第一位,因为它与一个=,然后是范围列year,然后是要检索的内容,即target。

从表中选择target,其中目标id=1,年份在2015年和2020年之间


通过只引用一次年份,您可以更快地完成查询。

从表中选择目标,其中目标id=1,年份在2015年和2020年之间


通过只引用一次年份,您可能会发现查询完成更快。

规则很简单。先用=测试事物。然后最多做一个范围。和BETWEEN在性能上等价于一对等价的不等式

更多讨论:

而且,正如GMB所指出的那样,扩大该指数使其覆盖范围又起到了推动作用。所有工作都在索引的BTree中完成;无需查看数据的BTree。因此,按照以下顺序:


规则很简单。先用=测试事物。然后最多做一个范围。和BETWEEN在性能上等价于一对等价的不等式

更多讨论:

而且,正如GMB所指出的那样,扩大该指数使其覆盖范围又起到了推动作用。所有工作都在索引的BTree中完成;无需查看数据的BTree。因此,按照以下顺序:


先用守门员。@TheImpler:你评论时我正在编辑。。。事实上,这取决于数据在列中的分布方式,例如,如果只有两个不同的目标,并且年分布超过100个离散值,则您希望年优先。OP并没有分享这些信息。在索引中包含目标字段是否会提高性能?哦,是的,确实如此。这叫做覆盖指数。它防止了MySQL的双索引查找问题。不需要,但如果你需要性能,就去做。那太棒了,谢谢你的提示!创建索引将查询从10秒减少到0.2秒。请先使用goalid。@TheImpler:我正在编辑,而您正在评论。。。事实上,这取决于数据在列中的分布方式,例如,如果只有两个不同的目标,并且年分布超过100个离散值,则您希望年优先。OP并没有分享这些信息。在索引中包含目标字段是否会提高性能?哦,是的,确实如此。这叫做覆盖指数。它防止了MySQL的双索引查找问题。不需要,但如果你需要性能,就去做。那太棒了,谢谢你的提示!创建索引将查询从10秒减少到0.2秒非常感谢提示!否。将=列放在第一位。这样,它将只接触索引中的连续行。各个列的基数并不重要。非常感谢您的提示!否。将=列放在第一位。这样,它将只接触索引中的连续行。各个列的基数并不重要。谢谢,我不知道queryNo。在解析语句或优化器时,BETWEEN实际上转换为另一种格式。请参阅“选择扩展的解释…”。。。;显示警告@休伯特请张贴您的节目创建表;对于我自己的深入分析,我们都将看到您当前的表格和
dex结构。Rick James,感谢您提供的详细信息以及您对MySQL如何工作的深入了解。谢谢,我不知道queryNo。在解析语句或优化器时,BETWEEN实际上转换为另一种格式。请参阅“选择扩展的解释…”。。。;显示警告@休伯特请张贴您的节目创建表;对于我自己的深入分析,我们都将看到您当前的表和索引结构。Rick James,感谢您提供的详细信息以及您对MySQL工作原理的深入了解。