2012-08-07 56 views
1

目前,我在data_article_key_terms表中有大约900,000个条目,以将关键术语与其各自的文章相关联。目标是能够选择任意日期范围,并根据该日期范围内的文章显示前15个关键字词。按频率和日期范围排列关键字

我正在运行的问题是,我正在运行的查询需要将近6秒,但我需要它比这更快。我意识到这是基于我正在运行的系统的相对基础,我可以使用更多功率的机器,但我试图在我走这条路线之前尽可能地优化它。

我使用InnoDB作为MySQL存储引擎来保持数据的完整性。据我了解,MyISAM的计数(*)更快,但使用该引擎也不是一种选择。

我也考虑过将关键项计数存储在基于固定时间范围的表中,但这最终会导致大量数据存储和跟踪。

有没有人有关于如何优化这种体验的好建议?

我有以下表格:

该表存储文章:

CREATE TABLE `data_article` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `connection_id` int(11) NOT NULL, 
    `folder_id` int(11) NOT NULL, 
    `user_id` int(11) NOT NULL, 
    `uid` varchar(100) NOT NULL, 
    `date` date NOT NULL, 
    `influencer_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `data_article_5930b15a` (`connection_id`), 
    KEY `data_article_4e5f642` (`folder_id`), 
    KEY `data_article_fbfc09f1` (`user_id`), 
    KEY `data_article_43ae76a1` (`influencer_id`), 
    KEY `data_article_date` (`date`), 
    CONSTRAINT `connection_id_refs_id_b2ae9152` FOREIGN KEY (`connection_id`) REFERENCES `account_connection` (`id`), 
    CONSTRAINT `folder_id_refs_id_e343586a` FOREIGN KEY (`folder_id`) REFERENCES `account_folder` (`id`), 
    CONSTRAINT `influencer_id_refs_id_45cd3615` FOREIGN KEY (`influencer_id`) REFERENCES `data_influencer` (`id`), 
    CONSTRAINT `user_id_refs_id_aca13cc9` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`) 
) 

此表存储关键术语:

CREATE TABLE `data_keyterm` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `term` varchar(100) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `data_keyterm_term` (`term`) 
) 

此表存储文章和关键术语之间的关系:

CREATE TABLE `data_article_key_terms` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `article_id` int(11) NOT NULL, 
    `keyterm_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    UNIQUE KEY `article_id` (`article_id`,`keyterm_id`), 
    KEY `data_article_key_terms_30525a19` (`article_id`), 
    KEY `data_article_key_terms_1d848ca4` (`keyterm_id`), 
    CONSTRAINT `article_id_refs_id_d87be8f5` FOREIGN KEY (`article_id`) REFERENCES `data_article` (`id`), 
    CONSTRAINT `keyterm_id_refs_id_50d233f8` FOREIGN KEY (`keyterm_id`) REFERENCES `data_keyterm` (`id`) 
) 

与该物品相关的该表存储有影响力:

CREATE TABLE `data_influencer` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `name` varchar(100) NOT NULL, 
    `title` varchar(100) NOT NULL, 
    `email` varchar(100) NOT NULL, 
    `active` tinyint(1) NOT NULL, 
    `user_id` int(11) NOT NULL, 
    PRIMARY KEY (`id`), 
    KEY `data_influencer_fbfc09f1` (`user_id`), 
    KEY `data_influencer_name` (`name`), 
    CONSTRAINT `user_id_refs_id_b1bb5d4f` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`) 
) 

这是SQL语句我使用基于时间范围内,他们组拉的关键字,并责令其按频率:

SELECT dk.id, dk.term as term, COUNT(dk.id) as count 
FROM data_keyterm dk 
INNER JOIN data_article_key_terms dakt ON dakt.keyterm_id = dk.id 
INNER JOIN data_article da ON da.id = dakt.article_id 
INNER JOIN data_influencer di ON di.id = da.influencer_id 
WHERE da.user_id = 1 
AND da.date between '2010-08-07' AND '2012-08-07' 
AND di.active = True 
GROUP BY dk.id 
ORDER BY count DESC 
LIMIT 15; 
+0

您最后的SQL语句看起来不是有效的GROUP BY语句。你可以仔细检查? – Olaf 2012-08-07 15:01:49

+0

是的,这是正确的,这个声明运行没有问题。 – bmorrise 2012-08-07 15:04:01

+0

@Olaf:这不是有效的SQL GROUP BY子句,但[它在MySQL中有效](http://dev.mysql.com/doc/refman/5.0/en/group-by-hidden-columns.html)。 – 2012-08-07 15:40:31

回答

0

运行带有900,000记录和3内连接的表的内连接将需要一些时间来执行。我认为你应该尝试一些外部搜索引擎如太阳能在快速时间获得结果

+0

Can Solr能处理这样的搜索吗? – bmorrise 2012-08-07 15:04:42

+0

是的,它处理。你有你创建索引正确获得这样的结果 – Ashish 2012-08-07 15:10:36

+0

谢谢你的Solr提示。我最终使用它,它运作得非常好。 – bmorrise 2014-08-08 13:39:43

0

我想知道,在这种情况下,索引可能没有帮助你。查询的选择性是什么?也就是说,正在使用多少文章/组合键?

为了优化性能,我认为查询计划应该按用户ID和日期选择文章,然后进行连接。然后将这个缩减的子集用于其他连接。相反,我怀疑它始终使用索引。

我的第一个建议是使用单个索引替换文章列表上的userid/date两个索引。 WHERE子句可以使用这个单个索引来满足条件。这可能会简化和改进查询计划。

要测试的另一件事是反规范文章/关键表一点。假设键和文章是同时创建的,请将用户标识和日期添加到此表中。然后,只需将您的查询改为对此表的限制即可。然后,您可以在用户标识和日期上有复合索引。但是,我不建议在这些领域有单独的索引。