Mysql 使用同一WHERE子句在同一个表上执行两个不同的查询

Mysql 使用同一WHERE子句在同一个表上执行两个不同的查询,mysql,sql,where,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 >=

我有两个不同的问题。但是它们都在同一个表中,并且都有相同的
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

如何提高效率?

因为两个查询都有不同的
GROUP BY
子句,它们本质上是不同的,不能组合。假设
timestamp
字段上已经存在索引,那么没有简单的方法可以提高效率


如果数据集很大(1000万行或更多行),那么在
国家、时间戳
上创建额外的组合索引可能会提高一些效率,但这不太可能是可测量的,如果这两个查询是一个接一个地直接执行的,那么MySQL本身的内存缓冲通常会减轻这种不足。

如果这个表的索引正确,那么整个表有多大就无关紧要了,因为您只查看今天的行

如果表的索引不正确,那么无论您做什么,这些查询的性能都将非常糟糕

您的
WHERE timestamp>=CURDATE()
子句意味着您需要在
timestamp
列上有一个索引。在您的一个查询中,
按国家分组
显示,
(时间戳,国家)
上的复合覆盖索引将非常有用

因此,一个复合索引
(时间戳,国家)
将满足您问题中的两个查询

让我们解释一下它是如何工作的。要查找今天的记录(或者任何以特定的
时间戳开始和结束的记录),并按国家对它们进行分组和计数,MySQL可以通过执行以下步骤来满足查询:

  • 随机访问与
    时间戳匹配的第一条记录的索引。O(对数n)
  • 从索引中获取第一个
    country
  • 扫描到索引中的下一个
    国家/地区
    值并计数。O(n)
  • 重复步骤三,直到
    时间戳
    范围结束
  • 这个索引扫描操作的速度与ace开发团队(MySQL团队)经过十年的努力所能达到的速度差不多。(你可能无法在周六下午超过他们。)MySQL通过索引的一小部分满足整个查询,所以它后面的表有多大并不重要

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

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

    您询问是否真的需要复合覆盖索引。你可能应该让他们工作,自己做决定


    显然,在选择索引时需要权衡。每个索引都会稍微减慢
    插入
    更新
    的过程,并且可以大大加快查询速度。只有您可以为您的特定应用程序进行权衡

    你认为这样做效率低吗?我不知道,但它们都获取了完全相同的列。自定义代码永远不会超过数据库对索引字段进行直接
    WHERE
    筛选。好吧,如果我在一个查询中获取所有结果,而不使用
    groupby
    ,然后自己检查这个数组,会怎么样?数据集很大,我同意第一段。如果没有进一步的细节,查询似乎没有问题。不过,我不同意第二段。复合索引允许MySQL所谓的“紧密索引扫描”处理GROUPBY子句,这比使用临时表(即使是较小的集合)要快得多。我认为严格的索引扫描也可以计算行数,但还没有测试。@Hazzit我知道这种优化,这就是我建议它的原因-我只是高度怀疑它会提高几毫秒以上,除非有数百万行,而且它可能更依赖于服务器配置(索引缓冲区的RAM和MySQL配置等)yoshi在一般代码中模拟数据库非常擅长的东西(特别是:管理和处理大型数据集),对于简单的任务来说,很少有比这更有效的。而且,我们也不可能给出一个明确的答案——这更多地取决于您的数据和配置,而不是其他任何东西。如果性能目前存在问题,请尝试进行比较,否则只需接受庞大的数据集并不总是返回即时结果。确定。另一个问题是,如果我像这样在查询中添加
    LIMIT
    ,按国家分组的LIMIT 10
    是否会提高性能?这是一个很棒的答案!在表中,我访问了商店。我在时间戳和国家上有正常的单独索引。我不确定是否也应该使用复合索引。我还想计算其他列,如查询2。例如:浏览器、窗口分辨率和语言。该表确实有很多INSERT(每个访问者)和UPDATE(例如,如果我想存储访问持续时间等)查询。@OllieJones“一个关于(时间戳,国家)的复合覆盖索引将非常有帮助。”不,不会是-时间戳“可能”是唯一的,这意味着,如果没有子排序,该索引不会按国家/地区的子排序添加任何内容。可能会在
    国家/地区、时间戳
    上添加一个额外索引。你还说“老实说,整个表有多大并不重要,因为你只看今天的行”,这从定义上来说也是不正确的,因为我可以说出很多每天点击率超过100万次的网站。