按频率和日期范围对关键字排名

时间:2012-08-07 14:49:03

标签: mysql database optimization innodb ranking

目前,我在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;

2 个答案:

答案 0 :(得分:0)

使用包含900,000条记录和3条内部联接的表运行内部联接将需要一些时间来执行。我认为你应该尝试像solar这样的外部搜索引擎来快速获得结果

答案 1 :(得分:0)

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

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

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

要测试的另一件事是对文章/密钥表进行非规范化。假设密钥和文章是同时创建的,请将用户ID和日期添加到此表中。然后,只需将您的查询重新定义为此表的限制。然后,您可以拥有关于用户ID和日期的综合索引。但是,我不建议在这些字段上使用单独的索引。