在我的html页面上,用户可以选择输入文本字符串,选中标记选项或同时执行这两项操作。然后将此数据放在显示数据的mysql查询中。
允许用户输入字符串的事实意味着我在mysql查询中使用LIKE函数。
如果我错了,请纠正我,但我相信LIKE功能可以减慢查询速度。 关于上面的陈述,我想知道LIKE函数中的空字符串是否会产生影响,例如:
select * from hello;
select * from hello where name like "%%";
如果它确实产生了显着差异(我相信这个数据库会越来越大),您对如何处理这个数据的想法是什么。
我的第一个想法是我将有2个查询: 一个具有类似功能 还有一个没有类似的功能。根据用户输入的内容,将调用正确的查询。
因此,例如,如果用户将搜索框留空,则不需要like函数,因此它将发送空字符,if语句将在其看到时选择其他选项(没有类似功能)有一个空字符。
有更好的方法吗?
答案 0 :(得分:2)
通常,LIKE
函数将很慢,除非它以固定字符串开头且列具有索引。如果执行LIKE 'foo%'
,它可以使用索引查找以foo
开头的所有行,因为MySQL索引使用B树。但是LIKE '%foo'
不能使用索引,因为B树只优化寻找前缀;这必须对整个表进行顺序扫描。
即使您使用带前缀的版本,性能改进也取决于该前缀减少了必须搜索的行数。如果您执行LIKE 'foo%bar'
,并且90%的行都以foo
开头,则仍需扫描表格的90%以测试它们是否以bar
结尾。
由于LIKE '%%'
没有固定的前缀,它将执行表的完整扫描,即使实际上没有要搜索的内容。最好是你的PHP脚本测试用户是否提供了搜索字符串,如果没有什么可以搜索的话,省略LIKE
测试。
答案 1 :(得分:0)
使用mysql软件发行版中的World数据库示例,我首先对带有和不带explain
子句的查询做了一个简单的where
,没有过滤效果:
mysql> explain select * from City;
mysql> explain select * from City where true;
mysql> explain select * from City where Name = Name;
在前三种情况下,结果如下:
+----+--------------+-------+------+----------------+-----+---------+-----+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+-------+------+----------------+-----+---------+-----+------+-------+
| 1 | SIMPLE | City | ALL | NULL | NULL | NULL | NULL | 4080 | |
+----+--------------+-------+------+----------------+-----+---------+-----+------+-------+
对于最后一次查询,我得到以下内容:
mysql> explain select * from City where Name like "%%";
+----+--------------+-------+------+----------------+-----+---------+-----+------+-------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------+-------+------+----------------+-----+---------+-----+------+-------+
| 1 | SIMPLE | City | ALL | NULL | NULL | NULL | NULL | 4080 | Using where |
+----+--------------+-------+------+----------------+-----+---------+-----+------+-------+
您可以看到,对于此特定查询,where条件未被优化掉。
我还进行了几次测量,以确定是否确实会有明显的差异,但是:
表只有4080行,我使用自交联接来渲染更长的计算时间
我使用having
子句来减少显示开销(1)。
测量结果:
mysql> select c1.Name, c2.Name from City c1, City c2 where concat(c1.Name,c2.Name) = concat(c1.Name,c2.Name) having c1.Name = "";
Empty set (5.22 sec)
上述查询以及true
或c1.Name = c1.Name
的查询在不到0.1秒的时间内表现明显相同。
mysql> reset query cache;
mysql> select c1.Name, c2.Name from City c1, City c2 where concat(c1.Name,c2.Name) like "%%" having c1.Name = "";
Empty set (13.80 sec)
在运行多次(在查询缓存重置之间)(2)时,这个时间也花了相同的时间。
显然,查询优化器没有看到后一种情况的机会。结论是你应该尽量避免使用该子句,即使它没有改变结果集。
(1):在从查询中合并数据后发生子句过滤,我认为它不应该改变实际的查询计算负载率。
(2):有趣的是,我最初尝试了一个简单的where c1.Name like ”%%"
,并在5.0
秒左右。时间结果,这让我尝试了一个更精细的条款。我不认为这个结果改变了整体结论;可能是在那种非常具体的情况下,过滤实际上具有有益的效果。希望mysql大师会解释这个结果。
答案 2 :(得分:0)
我相信LIKE函数可以减慢查询速度
我希望不是这样的。测试它有多难?
无论您运行哪个版本的查询,DBMS仍然必须检查表中的每一行。这将需要CPU的一些额外工作,但对于大型表,磁盘I / O将是限制因素。 LIKE '%%'
将丢弃具有空值的行 - 因此可能会减少DBMS在结果集/传输到客户端时需要保留的数据量,这可能会显着节省。
正如Barbar所说,提供没有前导通配符的表达式将允许DBMS使用对性能有重大影响的索引(如果有的话)。
很难从您的问题中得知(您没有提供示例查询/数据的方式,也没有提供应用程序的详细信息),但问题的解决方案可能是full text indexing