我有两张桌子:
Dictionary - 包含大约36,000个单词
CREATE TABLE IF NOT EXISTS `dictionary` (
`word` varchar(255) NOT NULL,
PRIMARY KEY (`word`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
数据 - 包含大约100,000行
CREATE TABLE IF NOT EXISTS `datas` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`hash` varchar(32) NOT NULL,
`data` varchar(255) NOT NULL,
`length` int(11) NOT NULL,
`time` int(11) NOT NULL,
PRIMARY KEY (`ID`),
UNIQUE KEY `hash` (`hash`),
KEY `data` (`data`),
KEY `length` (`length`),
KEY `time` (`time`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=105316 ;
我想以某种方式选择datas
中data
列包含1个或多个单词的所有行。
我理解这是一个很大的问题,它需要在每种可能的组合中将所有这些行匹配在一起,因此需要最佳的优化。
我已尝试过以下查询,但它只挂了很久:
SELECT `datas`.*, `dictionary`.`word`
FROM `datas`, `dictionary`
WHERE `datas`.`data` LIKE CONCAT('%', `dictionary`.`word`, '%')
AND LENGTH(`dictionary`.`word`) > 3
ORDER BY `length` ASC
LIMIT 15
我还尝试了类似于上面的左连接,以及指定like语句的on子句。
答案 0 :(得分:1)
这实际上不是一个简单的问题,您尝试执行的操作称为全文搜索,关系数据库不是执行此类任务的最佳工具。如果这是某种核心功能,请考虑使用专用于此类操作的解决方案,例如Sphinx Search Server。
如果这不是“关键任务”系统,您可以尝试其他方法。我可以看到datas.data列不是很长,因此您可以创建专用于您的任务的结构,并在操作使用期间继续维护它。例如,创建表:
dictionary_datas (
datas_id FK (datas.id),
word FK (dictionary.word)
)
现在,无论何时插入,删除或只是修改数据或字典表,您都可以更新dictionary_datas,其中包含哪些datas_id包含哪些单词(基本上多对多关系)。当然,这会降低您的性能,因此如果您的系统上的事务负载很高,则必须定期执行此操作。例如,放置一个每晚03:00运行的Cron Job并实现该表。为了简化任务,您可以将标志TO_CHECK添加到DATAS表中,并仅为那些具有1的记录实现数据(在您实现dictionary_datas之后将值切换为0)。请记住在更新DICTIONARY表后刷新整个DATAS表的方法。在数据处理方面,36 000和10 000并不是一个大数字。
拥有此表后,您可以像查询一样:
SELECT datas_id, count(*) AS words_num FROM dictionary_datas GROUP BY datas_id HAVING count(*) > 3;
为了加快查询速度(并减慢它的更新速度),您可以在其datas_id,word(完全按顺序)列上创建复合索引。如果您决定定期刷新数据,则应在刷新之前删除索引,而不是刷新数据,最后在刷新后最终创建索引 - 这种方式会更快。
答案 1 :(得分:0)
我不确定我是否理解你的问题,但我认为这可能是一个解决方案。此外,我认为人们不喜欢正则表达式,但这对我来说可以选择其值超过1个单词的列。
SELECT * FROM datas WHERE data REGEXP“([a-z])+”
答案 2 :(得分:0)
你试过这个吗?
select *
from dictionary, datas
where position(word,data) > 0
;
效率非常低,但对你来说可能还不错。 Here is a fiddle
为了获得更好的效果,您可以尝试在文本列DATA
上放置text search index,然后使用CONTAINS
函数代替POSITION
。