我有一个使用like
条件的查询,它正在查杀我的服务器
(这个查询是我在慢查询日志中经常得到的)
顺便说一下,我的表有大约120k行 - 请求忽略语法错误
select * from `images` where `category` like `%,3,%` and ( `tags` like '%,tag1,%' or `tags` like '%,tag2,%' or `tags` like '%,tag3,%' or `tags` like '%,tag4,%')
我现在不想更改查询和数据库设计,因此我决定切换到myisam并使用tags
列的全文索引。
之后服务器负载没有那么大变化,mysql仍然不时使用高达90%的cpu(8个诅咒中的1个)。
所以我喜欢这个全文索引......它是否会索引旧数据(在添加此索引之前)?因为它发生得非常快,我的桌子有点大。
或者它只能用于新存储的数据?
答案 0 :(得分:2)
全文索引通常仅对令牌上的前缀匹配有帮助。换句话说,tags
列的每一行中的所有非字母数字加下划线分隔的单词(AZ,0-9或_除以外的任何内容 - 请参阅here)将被编入索引用于前缀匹配。然后,您必须使用MATCH (tags) AGAINST ('tag1')
来匹配全文索引搜索。您可以为每个标记重复这些匹配,以获得完整查询。在完全配置匹配查询后,执行Explain查询将告诉您查询构建器是否正在使用索引。
不幸的是,MySQL在如何改变全文索引/搜索方面相当有限 - 所以你大多坚持使用它的默认搜索方法(全文有几种搜索模式 - 见docs)。
答案 1 :(得分:2)
现有数据已编入索引,但根据Pyrce的建议,LIKE %[token]%
的查询无法利用全文索引。
重写你的条件,这完全相当于你的初始查询(忽略stopwords and the likes):
WHERE MATCH(tags) AGAINST ('tag1 tag2 tag3 tag4' IN BOOLEAN MODE)
但是,您应该专注于规范化您的结构。在字段中存储非标量值(例如逗号分隔值)会违反first normal form。
创建一个新的image_tag
表并与images
建立1-N关系。常规索引将允许即时查询。
CREATE TABLE image_tags (
image_id INT,
tag VARCHAR(50),
PRIMARY KEY (image_id, tag),
FOREIGN KEY (image_id) REFERENCES images(id), -- replace with "images" table's actual primary key
KEY(tag, image_id) -- this index may be superfluous, check EXPLAIN
);
SELECT images.*
FROM images
JOIN image_tags ON image_id = images.id
WHERE tag IN ('tag1', 'tag2', 'tag3', 'tag4');
重复images.category
。