我的情况是这样的:
我有一个表(phrases
),大约有500,000个条目。每个条目都是一个短语:
Beating Around the Bush
Burst Your Bubble
Cry Wolf
Curiosity Killed The Cat
我还有另一张表(full_sen
)有4000个条目,其中每个条目都是一个带有短语的句子。
我希望匹配full_sen
表来查找哪些句子中有短语。
我需要经常运行,因为两个表都会定期有新的条目,我需要能够快速运行的东西。
最简单的查询是查看500k表并进行LIKE %phrase%
搜索
反对full_sen
表,但这需要永远......
我不介意合并PHP或Python,如果这会有所帮助;它不一定只是一个查询。
full_sen CREATE TABLE `full_sen` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(50) COLLATE utf8_unicode_ci NOT NULL,
`sku` varchar(21) COLLATE utf8_unicode_ci DEFAULT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `full_sen_sku_670bbe26026365f4_uniq` (`sku`),
KEY `full_sen_e8701ad4` (`user_id`),
CONSTRAINT `full_sen_user_id_295adcd84efdd880_fk_auth_user_id` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5232 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci
phrases CREATE TABLE `phrases` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`date` date NOT NULL,
`serial_number` varchar(20) NOT NULL,
`title` varchar(250) NOT NULL,
`status_number` smallint(5) unsigned,
PRIMARY KEY (`id`),
UNIQUE KEY `serial_number` (`serial_number`),
KEY `phrases_status_number_5f42a821_uniq` (`status_number`),
FULLTEXT KEY `title` (`title`)
) ENGINE=InnoDB AUTO_INCREMENT=632144 DEFAULT CHARSET=latin
名称和标题是我正在谈论的字段。
感谢。
答案 0 :(得分:1)
您可以采取两项措施来提高性能:预先计算和使用索引。它们中的每一个都会大大提高性能,甚至可以将它们组合在一起。那么让我们来看看:
正如您自己已经发现的那样,最简单的解决方案是循环遍历phrases
表,并且每行对LIKE %phrase%
表执行full_sen
(旁注:您:写了LIKE %sentence%
,但我认为这是一个错字 - 也许我稍后会编辑你的帖子。
但实际上,没有必要这样做。
创建名为phrase_sentence_pairs
的第三个表,其中包含列ID
(这只是行ID /主键),列phrase_id
和列sentence_id
。 phrase_id
和sentence_id
必须编入索引(非唯一)。当然,在开始时,您必须根据下面解释的算法用您已有的所有数据填充该表。这可能需要很长时间,但这应该无关紧要,因为它必须一次。
现在,当一个新短语添加到phrases
表时,您只需要扫描整个full_sen
表中的那个短语。每次短语包含在句子中时,您都会在phrase_sentence_pairs
表中添加一个新行,以便phrase_id
存储ID
表中新短语的phrases
和sentence_id
存储ID
表格当前匹配行的full_sen
。
同样,当一个新句子添加到full_sen
表时,你循环遍历phrases
表,并检查每一行是否包含在新句子中。如果是,则向phrase_sentence_pairs
表添加新行,以便sentence_id
存储ID
表中新句子的full_sen
和phrase_id
存储phrases
表的当前匹配行的ID。
就性能而言,这会导致以下情况:
您不再需要SELECT
和phrases
表中full_sen
了。相反,例如,当您想要查找给定短语的所有句子时,首先从ID
表中获取该短语的phrases
,然后从phrase_sentence_pairs
表中选择所有记录phrase_id
匹配的地方。
相反的操作(将所有短语提取到某个句子)的工作方式相同。
与以前相比,从phrase_sentence_pairs
表中选择将是闪电般快速的。这主要是因为数据库现在正在比较数字而不是部分匹配字符串,并且(更重要)因为可以使用索引来完成此SELECT
。
另一方面,插入会更慢。但总体性能提升仍将是激烈的:
我们假设SELECT
中phrase_sentence_pairs
所花费的时间可以忽略不计(在这种情况下这个假设是可以的),所以我们不会进一步考虑它。使用以前的版本,每次选择时都必须对LIKE
条记录进行500K * 4K
字符串比较。
相比之下,您现在必须在插入新短语时对LIKE
条记录进行4K
字符串比较(这意味着必须扫描的行数为500K(!) )和插入新句子时的500K
记录(根据必须扫描的行,这意味着4K
因子)。
即使我们考虑到我们现在必须在插入短语或句子时写入两个表而不是一个表,并且写入索引列当然比写入非索引列慢,我认为这是非常好。
如果插入仍然不够快,还有另一个技巧可以大大提高扫描速度。但在我详细说明之前,请先尝试我的建议并报告性能提升(最好在问题的最后添加)。
最后请注意,UPDATE
或phrases
表的full_sen
必须导致几乎相同的代码才能作为INSERT
运行,并且您必须在DELETE
到phrases
或full_sen
表后运行适当的代码。