【发布时间】:2020-02-21 03:08:21
【问题描述】:
我有这样定义的新闻表:
CREATE TABLE `news` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`creation_date` datetime DEFAULT NULL,
`modification_date` datetime DEFAULT NULL,
`active` bit(1) DEFAULT NULL,
`mark_for_delete` bit(1) DEFAULT NULL,
`verified` bit(1) DEFAULT NULL,
`bot_id` int(11) DEFAULT NULL,
`description` varchar(1000) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`hash` varchar(100) NOT NULL,
`published_at` datetime DEFAULT NULL,
`source` varchar(255) DEFAULT NULL,
`title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`url` varchar(511) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `UK_1dmji5m90xaiy84vttgkvsub2` (`hash`),
KEY `index_news_source` (`source`),
KEY `index_news_creation_date` (`creation_date`)
) ENGINE=InnoDB AUTO_INCREMENT=30887718 DEFAULT CHARSET=latin1
还有一个用于标记属于某些流行名称的新闻的连接表:
CREATE TABLE `star_news` (
`stars_id` bigint(20) NOT NULL,
`news_id` bigint(20) NOT NULL,
PRIMARY KEY (`stars_id`,`news_id`),
KEY `FK4eqjn8at6h4d9335q1plxkcnl` (`news_id`),
CONSTRAINT `FK1olc51y8amp8op1kbmx269bac` FOREIGN KEY (`stars_id`) REFERENCES `star` (`id`),
CONSTRAINT `FK4eqjn8at6h4d9335q1plxkcnl` FOREIGN KEY (`news_id`) REFERENCES `news` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
这是我返回最新消息的查询
SELECT DISTINCT n.*
FROM news n
JOIN star_news sn
ON n.id = sn.news_id
WHERE sn.stars_id IN (1234, 12345)
ORDER BY n.creation_date DESC
LIMIT 2;
解释:
+----+-------------+-------+------------+--------+-------------------------------------+---------+---------+-----------------------+------+----------+-----------------------------------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+-------+------------+--------+-------------------------------------+---------+---------+-----------------------+------+----------+-----------------------------------------------------------+
| 1 | SIMPLE | sn | NULL | range | PRIMARY,FK4eqjn8at6h4d9335q1plxkcnl | PRIMARY | 8 | NULL |196225| 100.00 | Using where; Using index; Using temporary; Using filesort |
| 1 | SIMPLE | n | NULL | eq_ref | PRIMARY | PRIMARY | 8 | cosmos_dev.sn.news_id | 1 | 100.00 | NULL |
+----+-------------+-------+------------+--------+-------------------------------------+---------+---------+-----------------------+------+----------+-----------------------------------------------------------+
这个查询在我的机器上需要 20 秒。如果我删除 order by 子句,它会在亚毫秒内返回。如何通过运行速度更快下订单?
我尝试在 creation_date 上使用强制索引,因为它是索引列,但它降低了性能
【问题讨论】:
-
问:根据您将运行的正常查询类型,在这种情况下,您正在执行 2 个 stars_id 值(1234、12345),如果您不应用按 creation_date 降序限制 2。
-
~196k(来自解释结果)
-
我认为不可能找到一个简单的“add-this-index”解决方案。此类索引不存在,因为您使用一个索引读取记录,并且需要按其他表中的其他字段对结果进行排序。
-
@akuzminsky 我想我可以在 star_news 中添加一个名为 news_date 的新列,并在 (news_id, news_date) 上创建一个索引。
-
您需要使用相同的索引进行阅读和排序。那么它会很快。所以,sn 表中必须是 (stars_id, news_date)。