2011-10-29 135 views
1

enter image description here优化一个缓慢的MySQL查询

我有一个MySQL查询,如下所示:

SELECT KeywordText, SUM(Frequency) AS Frequency FROM Keyword, Keyword_Polling_Frequency_Index 
WHERE Keyword.KeywordText 
IN ('deal', 'obama' and other keywords...) 
AND RSSFeedNo IN (106, 107 and other RSS feeds) 
AND PollingDateTime 
BETWEEN '2011-10-28 13:00:00' AND '2011-10-28 13:59:00' 
AND Keyword.KeywordNo = Keyword_Polling_Frequency_Index.KeywordNo 
GROUP BY Keyword.KeywordText 
ORDER BY Keyword.KeywordText ASC 

查询中使用由涉及到两个表,是为了得到一个频率每小时批处理程序给定小时的RSS源列表中的关键字列表。 Keyword_Polling_Frequency_Index表具有KeywordNo,RSSFeedNo和PollingDateTime的组合主键。查询将该表加入到包含KeywordText的关键字表中。 column keywordText有一个MySQL MyISAM全文索引。

在测试中,发现它的性能令人满意,但现在开始运行非常缓慢并影响应用程序页面的交互速度。当我检查MySQL日志时,我发现MySQL正在创建临时表。

所以,我的问题是,鉴于此查询必须处理数十个RSS源中的几十个关键字来计算频率,任何人都可以提出优化吗?

我曾想过通过关键字打破查询,但我不相信这一点的实用性。

任何人都可以帮忙吗?

我正在使用MySQL Community Edition 5.X,并且上面显示了此查询的一个版本的EXTENDED EXPLAIN。

SQL为表如下:

CREATE TABLE `keyword` (
`KeywordNo` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`KeywordText` varchar(64) NOT NULL, 
`UserOriginated` enum('TRUE','FALSE') NOT NULL, 
`Active` enum('TRUE','FALSE') NOT NULL, 
`UserNo` varchar(50) NOT NULL, 
`StopWord` enum('TRUE','FALSE') NOT NULL, 
`CreatedDate` date NOT NULL, 
`CreatedTime` time NOT NULL, 
PRIMARY KEY (`KeywordNo`), 
FULLTEXT KEY `KEYWORDTEXT` (`KeywordText`) 
) ENGINE=MyISAM AUTO_INCREMENT=44047 DEFAULT CHARSET=latin1$$ 


CREATE TABLE `keyword_polling_frequency_index` (
`KeywordNo` int(10) unsigned NOT NULL, 
`RSSFeedNo` int(10) unsigned NOT NULL, 
`PollingDateTime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
`Frequency` int(10) NOT NULL, 
`Active` enum('TRUE','FALSE') NOT NULL, 
`UserNo` varchar(50) NOT NULL, 
PRIMARY KEY (`KeywordNo`,`RSSFeedNo`,`PollingDateTime`), 
KEY `FK_keyword_polling_frequency_index_1` (`UserNo`), 
CONSTRAINT `FK_keyword_polling_frequency_index_1` FOREIGN KEY (`UserNo`) REFERENCES `user` (`UserNo`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=latin1$$ 
+0

这是非常真实的。 –

+0

已过帐表的SQL。 –

+0

我认为最好为'(KeywordNo,PollingDateTime)'创建一个复合索引(顺序很重要) – Karolis

回答

1

如前所述,在所提及的顺序添加一个索引到PollingDateTime字段。这是我的建议:

SELECT 
    K.KeywordText, 
    SUM(F.Frequency) AS Frequency 
FROM 
    Keyword K, Keyword_Polling_Frequency_Index F 
WHERE 
    EXISTS 
     (
     SELECT 1 
     FROM Keyword K1 
     WHERE 
      MATCH K1.KeywordText AGAINST ('deal obama "another keyword" yetanother' IN BOOLEAN MODE) 
      AND K1.KeywordNo = K.KeywordNo 
     ) 
    AND K.KeywordNo = F.KeywordNo 
    AND F.PollingDateTime BETWEEN '2011-10-28 13:00:00' AND '2011-10-28 13:59:00' 
    AND F.RSSFeedNo IN (106, 107, 110) 
    GROUP BY K.KeywordText 
    ORDER BY K.KeywordText ASC 

这可能会减少对,而不是直接匹配的两个表为(N×N)的比较(SQL内而外的解析)的记录数。

+0

我会在接下来的几天尝试这个,让你知道。另外,PollingDatetime将首先以主键顺序排列。 –

+0

我很想知道结果 – leon

+0

现在我要尝试一个快速和肮脏的运行。 –

0

如果你没有任何索引你应该创建相关的索引。

最小索引是keyword_polling_frequency_index.PollingDateTime

+0

我相信MySQL会自动为主键创建索引。当然,我在索引表中的键具有PRIMARY类型的索引。 –

+1

@MrMorgan是的,但问题是'PollingDateTime'处于PRIMARY索引的最后位置。这不适用于这个特定的查询。 – Karolis

+0

@Karolis:谢谢你。 –