mysql查询优化:带计数子查询的选择速度非常慢
我有以下表格:mysql查询优化:带计数子查询的选择速度非常慢,mysql,sql,query-optimization,Mysql,Sql,Query Optimization,我有以下表格: mysql> show create table rsspodcastitems \G *************************** 1. row *************************** Table: rsspodcastitems Create Table: CREATE TABLE `rsspodcastitems` ( `id` char(20) NOT NULL, `description` mediumtext,
mysql> show create table rsspodcastitems \G
*************************** 1. row ***************************
Table: rsspodcastitems
Create Table: CREATE TABLE `rsspodcastitems` (
`id` char(20) NOT NULL,
`description` mediumtext,
`duration` int(11) default NULL,
`enclosure` mediumtext NOT NULL,
`guid` varchar(300) NOT NULL,
`indexed` datetime NOT NULL,
`published` datetime default NULL,
`subtitle` varchar(255) default NULL,
`summary` mediumtext,
`title` varchar(255) NOT NULL,
`podcast_id` char(20) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `podcast_id` (`podcast_id`,`guid`),
UNIQUE KEY `UKfb6nlyxvxf3i2ibwd8jx6k025` (`podcast_id`,`guid`),
KEY `IDXkcqf7wi47t3epqxlh34538k7c` (`indexed`),
KEY `IDXt2ofice5w51uun6w80g8ou7hc` (`podcast_id`,`published`),
KEY `IDXfb6nlyxvxf3i2ibwd8jx6k025` (`podcast_id`,`guid`),
KEY `published` (`published`),
FULLTEXT KEY `title` (`title`),
FULLTEXT KEY `summary` (`summary`),
FULLTEXT KEY `subtitle` (`subtitle`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)
mysql> show create table station_cache \G
*************************** 1. row ***************************
Table: station_cache
Create Table: CREATE TABLE `station_cache` (
`Station_id` char(36) NOT NULL,
`item_id` char(20) NOT NULL,
`item_type` int(11) NOT NULL,
`podcast_id` char(20) NOT NULL,
`published` datetime NOT NULL,
KEY `Station_id` (`Station_id`,`published`),
KEY `IDX12n81jv8irarbtp8h2hl6k4q3` (`Station_id`,`published`),
KEY `item_id` (`item_id`,`item_type`),
KEY `IDXqw9yqpavo9fcduereqqij4c80` (`item_id`,`item_type`),
KEY `podcast_id` (`podcast_id`,`published`),
KEY `IDXkp2ehbpmu41u1vhwt7qdl2fuf` (`podcast_id`,`published`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
1 row in set (0.00 sec)
第二个表的“item_id”列是指前者的“id”列(两者之间没有外键,因为关系是多态的,即第二个表可能引用的实体不在第一个表中,但在其他类似但不同的表中)
我正在尝试获取一个查询,该查询列出第一个表中最近的项,而第二个表中没有任何对应项。到目前为止,我发现性能最高的查询是:
select i.*,
(select count(station_id)
from station_cache
where item_id = i.id) as stations
from rsspodcastitems i
having stations = 0
order by published desc
我还考虑过在不存在(…)的地方使用子查询来执行限制,但这实际上比我上面提到的要慢。但这仍然需要相当长的时间才能完成。MySQL的查询计划似乎没有使用可用的索引:
+----+--------------------+---------------+------+---------------+------+---------+------+--------+----------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+---------------+------+---------------+------+---------+------+--------+----------------+
| 1 | PRIMARY | i | ALL | NULL | NULL | NULL | NULL | 106978 | Using filesort |
| 2 | DEPENDENT SUBQUERY | station_cache | ALL | NULL | NULL | NULL | NULL | 44227 | Using where |
+----+--------------------+---------------+------+---------------+------+---------+------+--------+----------------+
请注意,查询的两部分都没有使用键
,而它应该能够使用主表中的键已发布(已发布)
,以及子查询的键项id(项id,项类型)
有什么建议可以让我在不等待几分钟的情况下获得适当的结果吗?您可能希望检测并删除表中的冗余索引。查看这两个表的创建表信息,可以帮助您发现几个,包括podcast\u id
,guid
和Station\u id
,已发布的,项目id
,项目类型
和podcast\u id
,已发布
可能还有更多。我认为最快的查询应该是:
select i.*
from rsspodcastitems i
where not exists (select 1
from station_cache sc
where sc.item_id = i.id
)
order by published desc;
这将利用station\u缓存(item\u id)
上的索引,或许还可以利用rsspodcastitems(published,id)
如果查询返回大量行,那么查询可能会更快。查询的措辞允许在rsspodcastitems(published)
上建立索引,以避免文件排序。如果删除分组依据
,则存在
版本应更快
我应该注意到,我喜欢你使用having
子句。在过去遇到这种情况时,我使用了一个子查询:
select i.*,
(select count(station_id)
from station_cache
where item_id = i.id) as stations
from (select i.*
from rsspodcastitems i
order by published desc
) i
where not exists (select 1
from station_cache sc
where sc.item_id = i.id
);
这允许一个索引进行排序
我希望您的方法有一点变化:
select i.*,
(exists (select 1
from station_cache sc
where sc.item_id = i.id
)
) as has_station
from rsspodcastitems i
having has_station = 0
order by published desc;
这应该比使用count()
的版本稍微快一点。我最终的解决方案是删除全文索引,并使用外部生成的索引表(通过迭代文本中的单词、过滤停止词和应用词干算法生成)来允许搜索。我不知道为什么全文索引会导致性能问题,但它们似乎会降低每个涉及表的查询的速度,即使它们没有被使用。我注意到了这些问题。我还注意到,每次我重新启动web服务器时,hibernate都会重新创建它们,所以我放弃了删除它们的尝试……很有趣。“explain select…”提供的分析表明,您的查询应该更快(因为它使用子查询索引,而我的子查询不使用索引),但在实际使用中,它仍然更慢。