我正在建立一个论坛,我正在寻找一种正确的方法来构建一个搜索功能,通过他们的名字或帖子的标题查找用户。我想出的是:
SELECT users.id, users.user_name, users.user_picture
FROM users, subject1, subject2
WHERE users.id = subject1.user_id
AND users.id = subject2.user_id
AND (users.user_name LIKE '%{$keywords}%'
OR subject1.title1 LIKE '%{$keywords}%'
OR subject2.title2 LIKE '%{$keywords}%')
ORDER BY users.user_name ASC
LIMIT 10
OFFSET {$offset}
LIMIT和OFFSET用于分页。我的问题是,当行数达到很大的数量时,通过多个表进行LIKE搜索会大大降低性能吗?
我有几个选择: 一,也许我可以重写该查询,以便在仅返回索引的user_id的子查询中完成LIKE搜索。然后,我会根据它找到剩余的用户信息。这会提高性能吗?
其次,我想我可以在第一个通配符之前显示$keyword
字符串,如LIKE {$keyword}%
中所示。这样,我可以索引user_name, title1, and title2
列。但是,由于我将在这里交换速度的准确性,这会产生多大的性能差异?索引这些列是否值得牺牲这么高的准确性?
第三,也许我可以为用户提供3个搜索字段供选择,并且每个搜索字段只能搜索一个表。这会提高性能吗?
最后,我应该考虑使用FULLTEXT搜索而不是LIKE吗?两者之间的性能差异是什么?此外,我的表使用InnoDB存储引擎,除非我切换到MyISAM,否则我无法使用FULLTEXT索引。切换到MyISAM会有什么重大差异吗?
分页是我担心的另一个性能问题,因为为了进行分页,我需要找到查询返回的结果总数。目前,我基本上是在做我刚刚提到的查询TWICE,因为它第一次仅用于COUNT
结果。
答案 0 :(得分:3)
您的查询中有两件事会阻止MySql使用索引首先您的模式以通配符%
开头,MySql不能使用索引来搜索以通配符开头的模式,其次您有{在OR
子句中,您需要使用WHERE
重写查询以避免使用OR,这也会阻止MySql使用索引。在不使用索引的情况下,MySql每次都需要进行全表扫描,并且所需的时间会随着表中行数的增加而线性增加,而且正如你所说的那样,“当行数增加时,它会大大降低性能达到了很大的数量“所以我说你唯一真正可扩展的选择是使用FULLTEXT搜索。
答案 1 :(得分:1)
您的大部分问题都在此解释:http://use-the-index-luke.com/sql/where-clause/searching-for-ranges/like-performance-tuning
InnoDB /全文索引是针对MySQL 5.6发布的,但这对你现在可能没什么帮助。
答案 2 :(得分:0)
从EXPLAIN <select-statement>
开始怎么样? http://dev.mysql.com/doc/refman/5.6/en/explain.html
答案 3 :(得分:0)
切换到MyISAM应该无法正常工作。唯一的缺点是,MyISAM在插入/更新时锁定整个表,这可能会使表中的插入速度慢于选择。基本上我的观点是,当你不需要外键时使用MyISAM并且表有比插入更多的选择,并且当表具有比选择更多的插入/更新时使用InnoDB(例如对于统计表) 。
在你的情况下,我认为切换到MyISAM是更好的选择,因为全文索引更强大,更快。
它还提供了使用某些查询修饰符的可能性,例如排除单词(“cat -dog
”)或类似内容。但请记住,不可能用LIKE-search(“*bar
”)来查找以短语结尾的单词。 “foo*
”会起作用。