mysql - 仅针对 Mysql 中的 1 列进行实时搜索 - 无需任何插件
问题描述
但是,我发现了一些关于此的线索,但没有适合我的情况。
我的移动应用程序中有一个搜索字段,在文本更改后,实时搜索通过调用我的 API 运行。
搜索请求仅在输入 3 个或更多字符时开始,并且仅在 1 个 DB 列中搜索,称为 TITLE。因此,每次用户输入一个字母时,都会有一个查询正在搜索它。
目前我有这样的(我知道这个解决方案非常糟糕)。$searchedword 是用户输入的单词:
if (!empty($searchedword)&&strlen($searchedword)>2 ) {$searchedword=strtolower($searchedword);
$sql = "SELECT * FROM TABLE ";$result = $mysqli->query($sql); $output='';
if ($result->num_rows > 0) {
while($data=$result->fetch_array()) {
$title=strtolower($data['title']);$content=$data['content'];
if (strpos($title,$searchedword) !== false ) {$output.=$title.','.$content;}
}}
所以这只是检查数据库中的标题是否包含搜索的单词。这很好用,但从性能上我认为它很糟糕,因为每次用户在搜索字段中输入一个字母时,每次都会查询表中的所有数据并查找该单词。
我想重新创建我的代码以满足最佳性能。
所以我的第一个问题是,我应该在 DB 的 TITLE 列中添加一个 FULLTEXT INDEX,它会有所帮助还是只会增加磁盘空间?因为我只是在搜索 1 列,而在此列中只是一个标题(最多 1 或 2 个字)。
第二个问题,对于我的案例,最好的查询应该是什么,当然还有最好的性能?因为我需要搜索用户输入的每个字母。
我可以这样使用搜索吗?
SELECT * FROM TABLE WHERE MATCH (title) AGAINST ('$searchedword' IN NATURAL LANGUAGE MODE)
但是看起来,只有当单词与标题完全匹配时才会返回,但当单词是标题的一部分时不返回任何内容,因此这不是一个好的解决方案。
唯一可行的解决方案是:
SELECT * FROM TABLE WHERE title LIKE '%$searchedword%' "
但是性能呢?而且我不明白这是如何工作的,因为 searchedword 被转换为小写字母,并且我已经从该单词中删除了重音符号,并且 DB 中的 TITLE 列有重音符号和大写字母,但是这个搜索效果很好!
解决方案
如果您的title
列具有类似 的排序规则utfmb4_general_ci
,则不必担心在 MySQLWHERE
子句中处理大写、小写和变音符号。MySQL 会为你做这件事。它非常擅长处理各种语言的字符集和排序规则。(这些东西对瑞典语用户很有帮助,MySQL 的发明者是瑞典人。)
FULLTEXT
withNATURAL LANGUAGE MODE
可能不是此应用程序的正确方法。它适用于单词,而不是字母块。因此,在您的用户输入整个单词而不是停用词之前,它可能不会给您任何东西。而且,当您搜索只有几行的表时,这有点松鼠。所以,如果你刚刚开始,这可能是个问题。
它确实按照匹配的紧密程度对结果进行排序,因此最有可能命中的是第一个。因此,如果您知道要搜索一个短语,那就太好了。
对于您的渐进式搜索应用程序,您可能希望使用这两个LIKE查询之一。
SELECT title FROM tbl WHERE title LIKE CONCAT('$searchedword', '%') /*insecure*/
或者这个慢得多,但在标题的任何地方都可以找到您的部分匹配,而不仅仅是在开头。
SELECT title FROM tbl WHERE title LIKE CONCAT('%', '$searchedword', '%') /*insecure*/
在您从用户那里收集到至少几封信之前,请避免运行这些查询,否则您会得到很多荒谬的结果。
在这些情况下说不SELECT title
,并在列SELECT *
上创建一个普通索引。title
这样 MySQL 就可以从索引中满足整个查询,这将使其更快。
并且,使用 MySQL 的WHERE
功能进行匹配。不要从 MySQL 中获取整个表并在您的 php 程序中搜索它。
并且,使用准备好的语句。因为网络蠕虫。
推荐阅读
- python - 为什么我的 DataGenerator 迭代的数据多于数据集的大小并给出 IndexError: list index out of range?
- angular - 动态更改角度 6 中的图标
- ansible - 在 kubernetes 命名空间中使用 ansible playbook 升级 helm
- django - Django 字段与多个抽象基类发生冲突
- c - 定时器触发 GPDMA 传输到 SRAM
- c# - 为什么字体被“包围”时不呈现在 HTML 中
- certificate - 使用自签名证书进行内核模式驱动程序签名
- reactjs - 在reactjs中提交之前无法更改状态值
- html - 无法设置动态创建的 .innerHTML (Angular)
- ssis - 尽管已将 -hostkey 开关添加到 WinSCP 命令行,但“主机密钥未验证”