[英]Two different queries on the same table with the same WHERE clause
我有两个不同的查询。 但是它们都在同一个表上,并且都具有相同的WHERE
子句。 因此,他们正在选择同一行。
查询1:
SELECT HOUR(timestamp), COUNT(*) as hits
FROM hits_table
WHERE timestamp >= CURDATE()
GROUP BY HOUR(timestamp)
查询2:
SELECT country, COUNT(*) as hits
FROM hits_table
WHERE timestamp >= CURDATE()
GROUP BY country
如何提高效率?
如果该表的索引正确,那么整个表有多大大小都没关系,因为您只查看今天的行。
如果表索引不正确,无论您做什么,这些查询的性能都会很糟糕。
您的WHERE timestamp >= CURDATE()
子句意味着您需要在timestamp
列上有一个索引。 在您的一个查询中, GROUP BY country
显示(timestamp, country)
的复合覆盖索引将有很大帮助。
因此,单个复合索引(timestamp, country)
将满足您问题中的两个查询。
让我们解释一下它是如何工作的。 为了查找今天的记录(或者实际上是任何以特定timestamp
值开始和结束的记录)并按国家/地区进行分组并计数,MySQL可以通过执行以下步骤来满足查询:
timestamp
匹配的第一条记录的索引。 O(log n)。 country
价值。 country
值并计数。 上)。 timestamp
范围结束。 这项索引扫描操作的速度与一组ace开发人员(MySQL团队)以十年的辛勤工作所能达到的速度一样快。 (您可能无法在星期六的下午超越它们。)MySQL只需一小部分索引就能满足整个查询,因此它背后的表有多大并不重要。
如果您在另一个查询之后立即运行其中一个查询,则MySQL仍有可能在RAM缓存中保留部分或全部索引数据块,因此它可能不必从磁盘重新获取它们。 这将提供更多帮助。
您看到示例查询如何以timestamp
吗? 最重要的WHERE
准则选择时间戳范围。 这就是为什么我建议的复合索引将timestamp
作为其第一列的原因。 如果没有任何以country
开头的查询,那么该列上的简单索引可能就没有用了。
您询问是否真的需要复合覆盖指数。 您可能应该阅读 有关它们如何工作的信息,并自己做出决定。
选择索引时显然需要权衡。 每个索引都会稍微减慢INSERT
和UPDATE
的过程,并且可以大大加快查询的速度。 只有您才能解决您的特定应用程序的权衡问题。
由于两个查询具有不同的GROUP BY
子句,因此它们本质上是不同的,因此无法合并。 假设timestamp
字段上已经存在索引,则没有直接的方法可以使此效率更高。
如果数据集很大(1000万或更多行),则可以通过对country, timestamp
创建额外的组合索引而获得一些额外的效率,但这不太可能被衡量,并且通常可以通过以下方法来缓解缺少的情况:如果这两个查询是在另一个查询之后直接执行的,则为MySQL本身提供内存缓冲。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.