Mysql 使用ORDER BY on DATETIME列优化查询

Mysql 使用ORDER BY on DATETIME列优化查询,mysql,sql,Mysql,Sql,下面的查询依赖于链接表中约4k行和注释表中约40k行的表,目前大约需要0.2秒的时间,考虑到没有那么多数据,这似乎相当慢 SELECT t1.id, t1.url, t1.dateAdded FROM links AS t1 LEFT JOIN comments AS t2 ON (t1.id = t2.linkId) WHERE COALESCE(t2.dateAdded, t1.dateAdded) <= "2020-03-22 20:04:45" GROUP BY t

下面的查询依赖于
链接
表中约4k行和
注释
表中约40k行的表,目前大约需要0.2秒的时间,考虑到没有那么多数据,这似乎相当慢

SELECT
    t1.id, t1.url, t1.dateAdded
FROM links AS t1 LEFT JOIN
comments AS t2
ON (t1.id = t2.linkId)
WHERE
    COALESCE(t2.dateAdded, t1.dateAdded) <= "2020-03-22 20:04:45"
GROUP BY t1.id
ORDER BY
    COALESCE(
        (
            SELECT
                MAX(dateAdded)
            FROM comments
            WHERE
                linkId = t1.id AND
                dateAdded <= "2020-03-22 20:04:45"
        ),
        t1.dateAdded
    ) DESC,
    t1.id DESC
    LIMIT 10
因此,我试图通过使用
EXPLAIN
找到差异,似乎唯一的差异在于
Extra
字段,其中对于
按t1排序。id
为空,对于
按t1排序。dateAdded
使用的是
临时;使用filesort
(注意,我在
t1.dateAdded上有索引)。不幸的是,我在解释这意味着什么以及如何优化原始查询方面有点困难。请注意,
id
INT(10)
dateAdded
DATETIME

一般来说,我想达到的目的是订购链接,以便最新的链接或链接与最新的评论是在顶部,“最新”的意思是相对于所提供的时间(即不考虑链接/评论之后添加)。 提前感谢您的帮助或提示

编辑:添加更多详细信息

EXPLAIN
用于使用
t1.id的简化查询

+------+-------------+-------+-------+---------------+------------+---------+--------------+------+-------------+
| id   | select_type | table | type  | possible_keys | key        | key_len | ref          | rows | Extra       |
+------+-------------+-------+-------+---------------+------------+---------+--------------+------+-------------+
|    1 | SIMPLE      | t1    | index | NULL          | PRIMARY    | 4       | NULL         | 3674 |             |
|    1 | SIMPLE      | t2    | ref   | fk_link_id    | fk_link_id | 5       | db1.t1.id    |    8 | Using where |
+------+-------------+-------+-------+---------------+------------+---------+--------------+------+-------------+
EXPLAIN
用于使用
t1.dateAdded进行简化查询

+------+-------------+-------+-------+---------------+------------+---------+--------------+------+---------------------------------+
| id   | select_type | table | type  | possible_keys | key        | key_len | ref          | rows | Extra                           |
+------+-------------+-------+-------+---------------+------------+---------+--------------+------+---------------------------------+
|    1 | SIMPLE      | t1    | index | NULL          | PRIMARY    | 4       | NULL         | 3674 | Using temporary; Using filesort |
|    1 | SIMPLE      | t2    | ref   | fk_link_id    | fk_link_id | 5       | db1.t1.id    |    8 | Using where                     |
+------+-------------+-------+-------+---------------+------------+---------+--------------+------+---------------------------------+
有关
链接的信息
表格:

CREATE TABLE `links` (
  `id` int(10) UNSIGNED NOT NULL,
  `url` varchar(2083) CHARACTER SET utf8mb4 NOT NULL,
  `dateAdded` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `links`
  ADD PRIMARY KEY (`id`),
  ADD KEY `dateAdded` (`dateAdded`);
CREATE TABLE `comments` (
  `id` int(10) UNSIGNED NOT NULL,
  `linkId` int(10) UNSIGNED DEFAULT NULL,
  `userId` int(10) UNSIGNED NOT NULL,
  `content` varchar(2000) CHARACTER SET utf8mb4 NOT NULL,
  `dateAdded` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `comments`
  ADD PRIMARY KEY (`id`),
  ADD KEY `fk_link_id` (`linkId`);

ALTER TABLE `comments`
  ADD CONSTRAINT `fk_link_id` FOREIGN KEY (`linkId`) REFERENCES `links` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
有关
注释的信息
表格:

CREATE TABLE `links` (
  `id` int(10) UNSIGNED NOT NULL,
  `url` varchar(2083) CHARACTER SET utf8mb4 NOT NULL,
  `dateAdded` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `links`
  ADD PRIMARY KEY (`id`),
  ADD KEY `dateAdded` (`dateAdded`);
CREATE TABLE `comments` (
  `id` int(10) UNSIGNED NOT NULL,
  `linkId` int(10) UNSIGNED DEFAULT NULL,
  `userId` int(10) UNSIGNED NOT NULL,
  `content` varchar(2000) CHARACTER SET utf8mb4 NOT NULL,
  `dateAdded` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

ALTER TABLE `comments`
  ADD PRIMARY KEY (`id`),
  ADD KEY `fk_link_id` (`linkId`);

ALTER TABLE `comments`
  ADD CONSTRAINT `fk_link_id` FOREIGN KEY (`linkId`) REFERENCES `links` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

首先,我可以指出,查询中的
分组依据
是不必要的(尽管没有错),因为您没有选择任何聚合。除此之外,我觉得只要使用
MAX()
作为分析函数,然后以此排序,您的生活就会变得更轻松。考虑这个版本:

WITH cte AS (
    SELECT t1.id, t1.url, t1.dateAdded,
        MAX(t2.dateAdded) OVER (PARTITION BY t1.id) maxDateAdded
    FROM links AS t1
    LEFT JOIN comments AS t2 ON t1.id = t2.linkId
    WHERE
        (t2.dateAdded IS NOT NULL AND t2.dateAdded <= '2020-03-22 20:04:45') OR
        (t2.dateAdded IS NULL AND t1.dateAdded <= '2020-03-22 20:04:45')
)

SELECT id, url, dateAdded
FROM cte
ORDER BY maxDateAdded DESC, t1.id DESC
LIMIT 10;

如果使用这些索引,将加快连接速度,并允许对
MAX
的调用快速求值。请注意,我已将
WHERE
子句重写为可排序,避免调用
COALESCE

请为这两个查询显示解释输出在执行之前,请向我们显示示例数据和预期输出。用简单的英语来说,
ORDER BY
子句的逻辑是什么?您应该使用禁用查询缓冲的tbh测试您的查询。该问题包括相关的
CREATE TABLE
CREATE INDEX
语句。另外@nbk和@TimBiegeleisen.Side注意:字符串和日期文字最好用单引号引起来。MySQL接受双引号,但几乎所有其他DBM都不接受。因此,使用单引号将使代码更易于移植。非常感谢您的回答!我可能把事情搞糊涂了,我有:
innodb_版本5.6.36-82.1
10.1.26-MariaDB-0+deb9u1
@leopik:MariaDB 10.2中引入了分析窗口函数:。您可能需要升级。