慢速MySQL按日期时间列排序
我有如下定义的新闻表:慢速MySQL按日期时间列排序,mysql,sql,innodb,Mysql,Sql,Innodb,我有如下定义的新闻表: 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` b
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秒。如果我删除ORDERBY子句,它将在亚毫秒内返回。如何通过加快运行速度来完成订单
我尝试在创建日使用force index,因为它是一个索引列,但它恶化了性能所以你有196k篇关于这两颗星的新闻文章?“额外解释”会告诉您发生了什么: 在何处使用;使用指数;使用临时设备;使用文件排序
MySQL正在创建一个临时文件并对其进行排序,以满足order by的要求,因为它无法使用索引来方便按日期加入和排序文章。那么您有196k篇与这两颗星相关的新闻文章?“额外解释”会告诉您发生了什么: 在何处使用;使用指数;使用临时设备;使用文件排序
MySQL正在创建一个临时文件并对其进行排序,以满足order by的要求,因为它无法使用索引来方便按日期加入和排序文章。首先,将查询编写为:
SELECT n.*
FROM news n
WHERE EXISTS (SELECT 1
FROM star_news sn
WHERE n.id = sn.news_id AND
sn.stars_id IN (1234, 12345)
)
ORDER BY n.creation_date DESC
LIMIT 2 ;
这样就消除了外部选择DISTINCT
,这应该会有所帮助
然后,在
star\u news(news\u id,stars\u id)
上创建索引。这还可以利用新闻(creation\u date desc,id)
上的索引。首先,将查询编写为:
SELECT n.*
FROM news n
WHERE EXISTS (SELECT 1
FROM star_news sn
WHERE n.id = sn.news_id AND
sn.stars_id IN (1234, 12345)
)
ORDER BY n.creation_date DESC
LIMIT 2 ;
这样就消除了外部选择DISTINCT
,这应该会有所帮助
然后,在
star\u news(news\u id,stars\u id)
上创建索引。这还可以利用news(creation\u date desc,id)
上的索引问:根据您将运行的正常查询类型,在这种情况下,您对两个stars\u id值(1234,12345)进行查询,如果您没有通过creation\u date descending应用限制2,那么将返回多少行总数。~196k(来自解释结果)我认为不可能找到一个简单的“添加此索引”解决方案。这样的索引不存在,因为您使用一个索引读取记录,并且需要按其他表中的其他字段对结果进行排序。@akuzminsky我想我可以向star_news添加一个名为news_date的新列,并在(news_id,news_date)上创建一个索引。您需要使用相同的索引进行读取和排序。那就快了。因此,它必须是sn表中的(stars_id,news_date)。Q:根据您将运行的正常查询类型,在这种情况下,您将对2个stars_id值(123412345)执行查询,如果不通过创建日期降序应用限制2,将返回多少行。~196k(从解释结果中)我认为不可能找到一个简单的方法“添加此索引”解决方案。此类索引不存在,因为您使用一个索引读取记录,并且需要按其他表中的其他字段对结果进行排序。@akuzminsky我想我可以向star_news添加一个名为news_date的新列,并在(news_id,news_date)上创建索引。您需要使用相同的索引进行读取和排序。这样会很快。因此,它必须是sn表中的(stars\u id,news\u date)。添加了comp索引。相同的解释计划,对新索引强制索引也没有帮助。。这不会有帮助。查询从一个表(sn)中按字段读取记录,并从另一个表(n)中按字段排序。添加了comp索引。相同的解释计划,对新索引强制索引也没有帮助。。那没有帮助。查询从一个表(sn)中按字段读取记录,并从另一个表(n)中按字段排序。但这会变成一个依赖子查询,除非最近写了两篇关于1234或12345的文章。@AndreasWederbrand…不一定。相关子查询通常是查询的最快实现。我一点也不知道为什么这么多人不理解。如果优化器选择扫描n
bycreation\u date
,它可能在检查30887718行时被卡住。但这会变成一个依赖子查询,除非新写了两篇关于1234或12345的文章。@AndreasWederbrand…不一定。相关子查询通常是查询的最快实现。我不喜欢测试为什么这么多人不理解这一点。如果优化器选择按creation\u date
扫描n
,它可能无法检查30887718行。