所以我有一个news_news
表(约16k行),每个news
可以分配许多teams
(约33k个关联)。
CREATE TABLE `news_news` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`title` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`body` longtext COLLATE utf8_unicode_ci NOT NULL,
`location` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`date` date NOT NULL DEFAULT '0000-00-00',
`status` char(1) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`slug` varchar(100) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',
`announcement` tinyint(1) NOT NULL DEFAULT '0',
`author_id` int(11) NOT NULL DEFAULT '0',
`priority` int(10) unsigned NOT NULL,
`embed` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
`source_url` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`source_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
`site_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `news_news_slug` (`slug`),
KEY `news_news_author_id` (`author_id`),
KEY `news_news_site_id` (`site_id`)
) ENGINE=InnoDB AUTO_INCREMENT=16521 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
CREATE TABLE `news_news_teams` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`news_id` int(10) unsigned NOT NULL,
`team_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `news_id` (`news_id`,`team_id`),
KEY `news_news_teams_news_id` (`news_id`),
KEY `news_news_teams_team_id` (`team_id`)
) ENGINE=InnoDB AUTO_INCREMENT=40393 DEFAULT CHARSET=latin1;
我想获得最近5条新闻,这些新闻是从一些团队中标记出来的;
SELECT
`news_news`.`id`, `news_news`.`title`, `news_news`.`body`, `news_news`.`embed`,
`news_news`.`location`, `news_news`.`date`, `news_news`.`priority`, `news_news`.`status`,
`news_news`.`slug`, `news_news`.`announcement`, `news_news`.`author_id`, `news_news`.`source_name`,
`news_news`.`source_url`, `news_news`.`site_id`
FROM `news_news`
INNER JOIN `news_news_teams` ON ( `news_news`.`id` = `news_news_teams`.`news_id` )
WHERE (
`news_news`.`status` = 'P'
AND `news_news_teams`.`team_id` IN (17, 18, 21, 27, 28, 31, 32, 34, 44, 51, 53,
56, 60, 65, 73, 75, 77, 80, 82, 83, 87, 89, 90, 92, 95, 98, 102, 105, 106,
110, 112, 116, 117, 120, 124, 127, 128, 130, 134, 138, 141, 146, 147, 152,
154, 156, 158, 161, 165, 166, 169, 170, 174, 176, 179, 181, 184, 185, 188,
194, 196, 203, 214, 220, 221, 228, 229, 230, 234, 235, 240, 245, 246, 249,
250, 251, 252, 257, 258, 260, 264, 266, 272, 273, 275, 276, 279, 280, 281,
283, 284, 285, 287, 294, 296, 297, 318, 319, 320, 326, 327, 330, 332, 334,
335, 336, 337, 350, 351, 368, 369, 373, 374, 375, 376, 377, 378, 383, 390,
393, 394, 395, 397, 398, 399, 400, 401, 405, 408, 410, 413, 416, 417, 418,
421, 425, 426, 427, 431, 434, 439, 440, 441, 443, 448, 451, 452, 453, 454,
457, 462, 477, 479, 482, 483, 484, 489, 491, 548, 566, 567, 10001792, 10007454))
ORDER BY `news_news`.`date` DESC
LIMIT 5;
以下是该查询的解释。
+----+-------------+-----------------+--------+---------------------------------------------------------+-------------------------+---------+----------------------------+------+--------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+--------+---------------------------------------------------------+-------------------------+---------+----------------------------+------+--------------------------------------------------------+
| 1 | SIMPLE | news_news_teams | range | news_id,news_news_teams_news_id,news_news_teams_team_id | news_news_teams_team_id | 4 | NULL | 4075 | Using index condition; Using temporary; Using filesort |
| 1 | SIMPLE | news_news | eq_ref | PRIMARY | PRIMARY | 4 | cs.news_news_teams.news_id | 1 | Using where |
+----+-------------+-----------------+--------+---------------------------------------------------------+-------------------------+---------+----------------------------+------+--------------------------------------------------------+
执行需要2秒多时间,有没有办法对其进行优化?
答案 0 :(得分:0)
在@ news_news.date
上添加索引作为@Octopi建议是一个好主意(因为我们按该字段排序),但在这种情况下仅仅说服mysql
使用{{1}是不够的索引。对我有用的解决方案是在date
中再添加一个过滤器,告诉WHERE
仅在上个月添加的mysql
中进行搜索。这使查询速度提高了5-7倍,现在执行约250毫秒。
news
PS。添加了SELECT
DISTINCT `news_news`.`id`, `news_news`.`title`, `news_news`.`body`, `news_news`.`embed`,
`news_news`.`location`, `news_news`.`date`, `news_news`.`priority`, `news_news`.`status`,
`news_news`.`slug`, `news_news`.`announcement`, `news_news`.`author_id`,
`news_news`.`source_name`, `news_news`.`source_url`, `news_news`.`site_id`
FROM `news_news`
INNER JOIN `news_news_teams` ON ( `news_news`.`id` = `news_news_teams`.`news_id` )
WHERE (
`news_news`.`status` = 'P'
AND `news_news`.`date` >= DATE_SUB(CURRENT_DATE, INTERVAL 1 MONTH)
AND `news_news_teams`.`team_id` IN (17, 18, 21, 27, 28, 31, 32, 34, 44, 51, 53, 56, 60,
65, 73, 75, 77, 80, 82, 83, 87, 89, 90, 92, 95, 98, 102, 105, 106, 110, 112, 116, 117,
120, 124, 127, 128, 130, 134, 138, 141, 146, 147, 152, 154, 156, 158, 161, 165, 166,
169, 170, 174, 176, 179, 181, 184, 185, 188, 194, 196, 203, 214, 220, 221, 228, 229,
230, 234, 235, 240, 245, 246, 249, 250, 251, 252, 257, 258, 260, 264, 266, 272, 273,
275, 276, 279, 280, 281, 283, 284, 285, 287, 294, 296, 297, 318, 319, 320, 326, 327,
330, 332, 334, 335, 336, 337, 350, 351, 368, 369, 373, 374, 375, 376, 377, 378, 383,
390, 393, 394, 395, 397, 398, 399, 400, 401, 405, 408, 410, 413, 416, 417, 418, 421,
425, 426, 427, 431, 434, 439, 440, 441, 443, 448, 451, 452, 453, 454, 457, 462, 477,
479, 482, 483, 484, 489, 491, 548, 566, 567, 10001792, 10007454)
) ORDER BY `news_news`.`date` DESC
LIMIT 5;
//and the explain
+----+-------------+-----------------+-------+---------------------------------------------------------+----------------+---------+-----------------+------+-----------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-----------------+-------+---------------------------------------------------------+----------------+---------+-----------------+------+-----------------------------------------------------+
| 1 | SIMPLE | news_news | range | PRIMARY,news_news_date | news_news_date | 3 | NULL | 190 | Using index condition; Using where; Using temporary |
| 1 | SIMPLE | news_news_teams | ref | news_id,news_news_teams_news_id,news_news_teams_team_id | news_id | 4 | cs.news_news.id | 1 | Using where; Using index; Distinct |
+----+-------------+-----------------+-------+---------------------------------------------------------+----------------+---------+-----------------+------+-----------------------------------------------------+
以排除重复的DISTINCT
。
答案 1 :(得分:0)
添加这两个;目前还不清楚哪个更好:
INDEX(status, news_id)
INDEX(status, date)
关于其他说明......
UNIQUE KEY
这是多余的,可以删除:
KEY `news_news_teams_news_id` (`news_id`),
这占用3个字节,虽然我怀疑你从不使用任何东西,但ascii标志(更改为CHARACTER SET ascii
):
`status` char(1) COLLATE utf8_unicode_ci NOT NULL DEFAULT '',