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

时间:2014-06-21 10:22:54

标签: mysql sql where

我有两个不同的查询。但它们都在同一个表中并且具有相同的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

如何提高效率?

2 个答案:

答案 0 :(得分:2)

如果这个表格被正确编入索引,那么说实话并不重要,因为你只是查看今天的行。

如果表格索引不正确,无论你做什么,这些查询的表现都会很糟糕。

您的WHERE timestamp >= CURDATE()子句意味着您需要在timestamp列上添加索引。在您的某个查询中,GROUP BY country显示覆盖(timestamp, country)上的索引的化合物将是一个很好的帮助。

因此,单个复合索引(timestamp, country)将满足您问题中的两个查询。

让我们解释一下这是如何运作的。要查找今天的记录(或者实际上任何以特定timestamp值开头和结尾的记录)并按国家/地区对它们进行分组,并对它们进行计数,MySQL可以通过以下步骤来满足查询:

  1. 将索引随机访问到与timestamp匹配的第一条记录。 O(log n)。
  2. 从索引中获取第一个country
  3. 扫描到索引中的下一个country并计数。为O(n)。
  4. 重复第3步,直到timestamp范围结束。
  5. 这种索引扫描操作的速度与ace开发人员团队(MySQL团队)可以通过十年的努力工作一样快。 (你可能无法在星期六下午超越它们。)MySQL用一小部分索引来满足整个查询,所以它背后的表有多大并不重要。

    如果你一个接一个地运行其中一个查询,MySQL可能仍然会在RAM缓存中有一些或所有索引数据块,因此它可能不必从磁盘重新获取它们。这将有助于实现更多目标。

    您是否看到了示例查询如何通过timestamp引导?最重要的WHERE标准选择时间戳范围。这就是为什么我建议的复合索引有timestamp作为第一列。如果您没有任何带有country的查询,那么您对该列的简单索引可能毫无用处。

    你问你是否真的需要复合覆盖指数。您可能read about how他们的工作并为您自己做出决定。

    在选择索引时,显然需要权衡利弊。每个索引都会使INSERTUPDATE的过程变慢,并且可以大大加快查询速度。只有您可以为您的特定应用程序进行权衡。

答案 1 :(得分:0)

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

如果数据集很大(1000万或更多行),那么可能country, timestamp上制作额外的组合索引时获得一点额外的效率,但这不太可能是可测量的,如果这两个查询直接在另一个查询之后执行,那么MySQL本身的内存缓冲通常可以减轻它的缺失。