MySQL ORDER BY 使用 SUBQUERY 比使用 PLAIN 简单查询执行得更好

发布于 2025-01-13 05:17:03 字数 3741 浏览 3 评论 0原文

由于某种原因,我不明白这个普通的常规 MySQL 查询运行速度比预期慢。据我了解,MySQL 首先使用 WHERE 对查询集进行切片,然后对结果子集进行排序。我得到的印象是不同的(?)。也许“优化”查询的输出并不准确,即使它返回同一行。没有 ORDER BY 子句的相同查询运行得非常快。

Server version:     5.6.10 MySQL Community Server (GPL)

这是查询:

SELECT *
FROM `core_tweet`
WHERE `core_tweet`.`streamer_id` = 44566
ORDER BY `platform_id`
LIMIT 1;
1 row in set (27.84 sec)
rerun with SQL_NO_CACHE (46.39 sec)

这是现在“优化”的查询:

SELECT *
FROM  (
  SELECT *
  FROM `core_tweet`
  WHERE `core_tweet`.`streamer_id` = 44566
) sub
ORDER BY sub.platform_id ASC
LIMIT 1;
1 row in set (0.56 sec)
rerun with SQL_NO_CACHE (3.82 sec)

以及它们各自的 EXPLAIN 输出:

+----+-------------+------------+-------+-----------------------------------------------------+-------------+---------+------+------+-------------+
| id | select_type | table      | type  | possible_keys                                       | key         | key_len | ref  | rows | Extra       |
+----+-------------+------------+-------+-----------------------------------------------------+-------------+---------+------+------+-------------+
|  1 | SIMPLE      | core_tweet | index | core_tweet_streamer_id_51082c18_fk_core_streamer_id | platform_id | 402     | NULL |  462 | Using where |
+----+-------------+------------+-------+-----------------------------------------------------+-------------+---------+------+------+-------------+


+----+-------------+------------+------+-----------------------------------------------------+-----------------------------------------------------+---------+-------+-------+----------------+
| id | select_type | table      | type | possible_keys                                       | key                                                 | key_len | ref   | rows  | Extra          |
+----+-------------+------------+------+-----------------------------------------------------+-----------------------------------------------------+---------+-------+-------+----------------+
|  1 | PRIMARY     | <derived2> | ALL  | NULL                                                | NULL                                                | NULL    | NULL  | 52072 | Using filesort |
|  2 | DERIVED     | core_tweet | ref  | core_tweet_streamer_id_51082c18_fk_core_streamer_id | core_tweet_streamer_id_51082c18_fk_core_streamer_id | 5       | const | 52072 | NULL           |
+----+-------------+------------+------+-----------------------------------------------------+-----------------------------------------------------+---------+-------+-------+----------------+

这是表:

CREATE TABLE `core_tweet` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `created_at` datetime(6) NOT NULL,
  `updated_at` datetime(6) NOT NULL,
  `published_at` datetime(6) NOT NULL,
  `platform_id` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  `text` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `retweet_count` bigint(20) DEFAULT NULL,
  `favorite_count` bigint(20) DEFAULT NULL,
  `hashtags` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `tweet_url` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `streamer_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `platform_id` (`platform_id`),
  KEY `core_tweet_streamer_id_51082c18_fk_core_streamer_id` (`streamer_id`),
  CONSTRAINT `core_tweet_streamer_id_51082c18_fk_core_streamer_id` FOREIGN KEY (`streamer_id`) REFERENCES `core_streamer` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26267613 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

表统计信息:

core_tweet row count: 25856893
core_tweet `WHERE streamer_id = 44566` row count: 25868
core_streamer row count: 47203

For some reason I don't understand this plain regular MySQL query runs SLOWER than expected. From what I understood, MySQL would first slice the queryset using WHERE then sort the subset of results. The impression I get is something different (?). Perhaps the output of the "optimized" query is NOT trustable to be accurate even though it's returning the same row. The same query without the ORDER BY clause runs really fast.

Server version:     5.6.10 MySQL Community Server (GPL)

This is the query:

SELECT *
FROM `core_tweet`
WHERE `core_tweet`.`streamer_id` = 44566
ORDER BY `platform_id`
LIMIT 1;
1 row in set (27.84 sec)
rerun with SQL_NO_CACHE (46.39 sec)

This is the now "optimized" query:

SELECT *
FROM  (
  SELECT *
  FROM `core_tweet`
  WHERE `core_tweet`.`streamer_id` = 44566
) sub
ORDER BY sub.platform_id ASC
LIMIT 1;
1 row in set (0.56 sec)
rerun with SQL_NO_CACHE (3.82 sec)

And their respective EXPLAIN outputs:

+----+-------------+------------+-------+-----------------------------------------------------+-------------+---------+------+------+-------------+
| id | select_type | table      | type  | possible_keys                                       | key         | key_len | ref  | rows | Extra       |
+----+-------------+------------+-------+-----------------------------------------------------+-------------+---------+------+------+-------------+
|  1 | SIMPLE      | core_tweet | index | core_tweet_streamer_id_51082c18_fk_core_streamer_id | platform_id | 402     | NULL |  462 | Using where |
+----+-------------+------------+-------+-----------------------------------------------------+-------------+---------+------+------+-------------+


+----+-------------+------------+------+-----------------------------------------------------+-----------------------------------------------------+---------+-------+-------+----------------+
| id | select_type | table      | type | possible_keys                                       | key                                                 | key_len | ref   | rows  | Extra          |
+----+-------------+------------+------+-----------------------------------------------------+-----------------------------------------------------+---------+-------+-------+----------------+
|  1 | PRIMARY     | <derived2> | ALL  | NULL                                                | NULL                                                | NULL    | NULL  | 52072 | Using filesort |
|  2 | DERIVED     | core_tweet | ref  | core_tweet_streamer_id_51082c18_fk_core_streamer_id | core_tweet_streamer_id_51082c18_fk_core_streamer_id | 5       | const | 52072 | NULL           |
+----+-------------+------------+------+-----------------------------------------------------+-----------------------------------------------------+---------+-------+-------+----------------+

This is the table:

CREATE TABLE `core_tweet` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `created_at` datetime(6) NOT NULL,
  `updated_at` datetime(6) NOT NULL,
  `published_at` datetime(6) NOT NULL,
  `platform_id` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL,
  `text` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `retweet_count` bigint(20) DEFAULT NULL,
  `favorite_count` bigint(20) DEFAULT NULL,
  `hashtags` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL,
  `tweet_url` varchar(250) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  `streamer_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `platform_id` (`platform_id`),
  KEY `core_tweet_streamer_id_51082c18_fk_core_streamer_id` (`streamer_id`),
  CONSTRAINT `core_tweet_streamer_id_51082c18_fk_core_streamer_id` FOREIGN KEY (`streamer_id`) REFERENCES `core_streamer` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=26267613 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

Tables stats:

core_tweet row count: 25856893
core_tweet `WHERE streamer_id = 44566` row count: 25868
core_streamer row count: 47203

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

幸福还没到 2025-01-20 05:17:03

这甚至可以让第一个版本运行得更快:

KEY(streamer_id) 替换为

INDEX(streamer_id, platform_id)

This may allow even the first version to run faster yet:

Replace KEY(streamer_id) with

INDEX(streamer_id, platform_id)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文