SQL 查询优化

SQL queries optimization

我在优化某些考虑了日期时间字段的 sql 查询时遇到问题。

首先,我的table结构如下:

  CREATE TABLE info (
  id int NOT NULL auto_increment,
  name varchar(20),
  infoId int,
  shortInfoId int,
  text varchar(255),
  token varchar(60),
  created_at DATETIME,
  PRIMARY KEY(id)
  KEY(created_at));

在对一些简单查询使用解释后,我添加了 created_at 键,这提高了我大部分简单查询的性能。我现在遇到以下查询的问题:

SELECT min(created_at), max(created_at) from info order by id DESC limit 10000

通过此查询,我想获得最后 10k 个结果之间的时间跨度。

使用 explain 后得到以下结果:

id  select_type     table   type    possible_keys   key     key_len     ref     rows    Extra
1   SIMPLE          info    ALL     NULL            NULL    NULL        NULL     4       NULL

关于如何提高此查询的性能的任何想法?

SELECT min(created_at), max(created_at) from info order by id DESC limit 10000

以上查询将为您提供一行,其中包含 info table 中的最小值和最大值 created_at。因为它只有 returns 1 行,order by 和 limit 子句不起作用。

倒数第10000条记录可以用order by & limit条件ORDER BY id DESC LIMIT 1 OFFSET 9999访问(感谢@Mörre Noseshine指正)

因此,我们可以将预期的查询写成如下:

SELECT 
min_created_at.value, 
max_created_at.value
FROM 
(SELECT 
    created_at value 
 FROM info 
 ORDER BY id DESC 
 LIMIT 1 OFFSET 9999) min_created_at,

(SELECT 
    created_at value 
 FROM info 
 ORDER BY id DESC 
 LIMIT 1) max_created_at

如果您想检查按 id 排序的前 10k 行,那么您需要使用子查询来实现您的目标:

SELECT MIN(created_at), MAX(created_at)
FROM (
    SELECT created_at
    FROM info
    ORDER BY id DESC
    LIMIT 10000
) tenK

内部查询从 table 中获取前 10k 行,按 id 排序(只需要 created_at 字段)。外部 table 从内部查询生成的结果集中计算 created_at 的最小值和最大值。

我没有 运行 一个 EXPLAIN 但我认为它在 'Extra' 列中说 'Using temporary' (这不好,但你不能做得更好对于此请求)。但是,10,000 行并不算多;它 运行 速度很快,并且性能不会随着 table 大小的增加而降低。

更新:

现在我注意到问题中的这句话:

With this query I want to get the timespan between tha last 10k results.

如果你想获取最近行的 created_at 的值和过去 10k 行的行,那么你可以使用两个简单的查询,这些查询使用 created_at 上的索引运行 快:

(
    SELECT created_at
    FROM info
    ORDER BY id DESC
    LIMIT 1
)
UNION ALL
(
    SELECT created_at
    FROM info
    ORDER BY id DESC
    LIMIT 9999,1
)
ORDER BY created_at

这个查询产生2行,第一行是过去第10000行的created_at的值,第二行是最近一行的created_at的值(我假设created_at 总是在增长)。