繁体   English   中英

具有相同WHERE子句的同一表上的两个不同查询

[英]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可以通过执行以下步骤来满足查询:

  1. 随机访问与timestamp匹配的第一条记录的索引。 O(log n)。
  2. 从指数中获取第一country价值。
  3. 扫描到索引中的下一个country值并计数。 上)。
  4. 重复第三步,直到timestamp范围结束。

这项索引扫描操作的速度与一组ace开发人员(MySQL团队)以十年的辛勤工作所能达到的速度一样快。 (您可能无法在星期六的下午超越它们。)MySQL只需一小部分索引就能满足整个查询,因此它背后的表有多大并不重要。

如果您在另一个查询之后立即运行其中一个查询,则MySQL仍有可能在RAM缓存中保留部分或全部索引数据块,因此它可能不必从磁盘重新获取它们。 这将提供更多帮助。

您看到示例查询如何以timestamp吗? 最重要的WHERE准则选择时间戳范围。 这就是为什么我建议的复合索引将timestamp作为其第一列的原因。 如果没有任何以country开头的查询,那么该列上的简单索引可能就没有用了。

您询问是否真的需要复合覆盖指数。 您可能应该阅读 有关它们如何工作的信息,并自己做出决定。

选择索引时显然需要权衡。 每个索引都会稍微减慢INSERTUPDATE的过程,并且可以大大加快查询的速度。 只有您才能解决您的特定应用程序的权衡问题。

由于两个查询具有不同的GROUP BY子句,因此它们本质上是不同的,因此无法合并。 假设timestamp字段上已经存在索引,则没有直接的方法可以使此效率更高。

如果数据集很大(1000万或更多行),则可以通过对country, timestamp创建额外的组合索引而获得一些额外的效率,但这不太可能被衡量,并且通常可以通过以下方法来缓解缺少的情况:如果这两个查询是在另一个查询之后直接执行的,则为MySQL本身提供内存缓冲。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM