我正在运行此查询来搜索数据库:
SELECT
IFNULL(firstname, '') AS firstname,
IFNULL(lastname, '') AS lastname,
IFNULL(age, ' ') AS age,
email,
telephone,
comments,
ref
FROM person
RIGHT JOIN
order ON person.oID = order.ref
WHERE
LOWER(firstname) LIKE LOWER ('%{$search}%') OR
LOWER(lastname) LIKE LOWER ('%{$search}%') OR
LOWER(email) LIKE LOWER ('%{$search}%') OR
LOWER(telephone) LIKE LOWER ('%{$search}%') OR
LOWER(ref) LIKE LOWER ('%{$search}%');
它正在进行大量处理,但我怎样才能更快地获得这些结果?该页面加载大约需要6-7秒,如果我在PHPMyAdmin中运行查询,则查询需要3-4秒才能运行。它不是一个庞大的数据库,3000条左右。我已为ref
,email
,firstname
和lastname
列添加了索引,但这似乎没有任何区别。有人可以帮忙吗?
答案 0 :(得分:1)
这个查询速度慢的原因是因为你以最慢的方式结合了MySQL的两个方便但缓慢的功能。
FUNCTION(column)
LIKE %matchstring%
需要扫描表格;没有有序的索引可以帮助满足此搜索,因为它没有固定。
condition
或condition
或condition
要求每个OR
子句重新扫描一次表。
如果您正确设置了列排序规则,那么您也忽略了MySQL的搜索已经不区分大小写的事实。
最后,我们不清楚您对RIGHT JOIN
ed表格数据的处理方式。结果集的哪些列来自该表?如果您不需要该表中的数据,请将其删除。
总而言之,你所拥有的是慢x多。
那么,你怎么解决这个问题呢?最重要的是让你尽可能多地摆脱这些无法扫描的扫描。如果你可以改为
email LIKE '{$search}%'
因此可以消除LOWER()
条款中的%
个函数和前导LIKE
,您将获得巨大的胜利。
如果这种广播网络搜索功能对您的应用程序至关重要,您应该考虑使用MySQL全文搜索。
或者您可以考虑在表格中创建一个新列,该列是您当前搜索的所有列的串联,因此您只需搜索一次。
编辑以解释LIKE
慢度
如果列haystack
已编入索引,则搜索haystack LIKE 'needle%'
会很快运行。这是因为BTREE风格指数本身就是有序的。要以这种方式搜索,MySQL可以随机访问第一个可能的匹配,然后按顺序扫描到最后一个可能的匹配。
但搜索haystack LIKE '%needle%'
无法使用随机访问来查找索引中的第一个可能匹配项。第一场可能的比赛可能在任何地方。因此,必须逐一扫描haystack
needle
的所有值。
答案 1 :(得分:1)
我建议您将right join
更改为inner join
。您正在查找的字段看起来无论如何都来自person
表,因此where
子句将查询转换为内连接。
SELECT
IFNULL(firstname, '') AS firstname,
IFNULL(lastname, '') AS lastname,
IFNULL(age, ' ') AS age,
email,
telephone,
comments,
ref
FROM person INNER JOIN
order
ON person.oID = order.ref
WHERE
LOWER(firstname) LIKE LOWER ('%{$search}%') OR
LOWER(lastname) LIKE LOWER ('%{$search}%') OR
LOWER(email) LIKE LOWER ('%{$search}%') OR
LOWER(telephone) LIKE LOWER ('%{$search}%') OR
LOWER(ref) LIKE LOWER ('%{$search}%');
其次,在order(ref)
上创建索引。这应该会大大减少where
子句的搜索空间。语法是:
create index order_ref on `order`(ref);
顺便说一句,order
是表的错误名称,因为它是一个SQL保留字。我建议改为orders
。
答案 2 :(得分:0)
为什么不使用全文搜索而不是一堆OR和LOWER?
SELECT
IFNULL(firstname, '') AS firstname,
IFNULL(lastname, '') AS lastname,
IFNULL(age, ' ') AS age,
email,
telephone,
comments,
ref
FROM person
RIGHT JOIN
order ON person.oID = order.ref
WHERE
MATCH (LOWER(firstname), LOWER(lastname),LOWER(email),LOWER(ref))
AGAINST ('$search' IN BOOLEAN MODE)
要更快地运行,您需要添加索引。
ALTER TABLE person ADD FULLTEXT(firstname, lastname,email,ref);