SQL样性能仅仅通配符的(%)作为一个值
-
05-07-2019 - |
题
我想知道什么是业绩的一查询将是喜欢使用象的关键词和通配符的价值相比,具有不在条款。
考虑在条款,如"其中一个LIKE'%'".这将符合所有可能的价值观列'a'。这是如何比较不具有的其中的条款。
我之所以问这个问题是,我有一个应用程序,其中有一些领域,可能用户指定的数值来搜索。在某些情况下使用者将像所有可能的结果。我目前正在使用一个单一的查询是这样的:
SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?
值的'%'和'%'可以提供给符合所有可能值,或b。这是方便,因为我可以使用一个单一的名查询在我的应用程序。我不知道是什么性能的考虑。不查询的优化程序减少LIKE'%'要简单地匹配吗?我知道因为我使用一个名为查询(准备的发言),这也可能影响的答案。我意识到的回答是有可能的数据库具体。所以,具体而言如何将这项工作在Oracle,MS SQL服务器和德比。
备选办法,这将使用3个单独的查询依据用户输入的配符。
一个是通配符查询:
SELECT * FROM TableName WHERE b LIKE ?
B配符查询:
SELECT * FROM TableName WHERE a LIKE ?
A和B是通配符:
SELECT * FROM TableName
没有通配符:
SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?
显然具有一个单一的查询是最简单和最容易维持。我宁愿使用这一查询,如果业绩仍然是好的。
解决方案 3
我希望有一本教科书可以回答这个问题,但听起来它会因不同的数据库类型而有所不同。大多数回复表明我应该进行测试,这正是我所做的。
我的应用程序主要针对Derby,MS SQL和Oracle数据库。由于德比可以嵌入式运行并且易于设置,因此我首先测试了性能。结果令人惊讶。我针对一个相当大的表测试了最坏的情况。我运行了1000次测试并对结果取平均值。
查询1:
SELECT * FROM TableName
查询2(值为a ="%"和b ="%"):
SELECT * FROM TableName WHERE a LIKE ? AND b LIKE ?
查询1平均时间:178毫秒
查询2平均时间:181毫秒
因此德比的表现在两个查询之间几乎相同。
其他提示
SQL Server通常会看到
WHERE City LIKE 'A%'
并将其视为
WHERE City >= 'A' AND City < 'B'
...并且如果合适的话,愉快地使用索引搜索。我说'一般',因为我看到它在某些情况下没有做到这种简化。
如果有人试图这样做:
WHERE City LIKE '%ville'
...然后索引搜索基本上是不可能的。
但有些简单:
WHERE City LIKE '%'
将被视为等同于:
WHERE City IS NOT NULL
您可以使用DBMS提供的任何查询分析(例如
, MS SQL的 SET SHOWPLAN_ALL ON
(或者使用其他方法), for Oracle的EXPLAIN PLAN FOR
),以了解查询的执行方式。
任何有价值的DBMS都会在尝试运行查询之前删除 LIKE'%'
子句。我很确定我已经看到DB2 / z在其执行计划中执行此操作。
准备好的语句应该没有区别,因为它应该在到达执行引擎之前变成真正的 SQL。
但是,与所有优化问题一样,衡量,不要猜测!存在DBA是因为它们根据实际数据(随时间变化)不断调整DBMS。至少,你应该用适当的静态数据计算所有变化的时间(并获得执行计划),看看是否存在差异。
我知道这样的查询:
select c from t where ((1 = 1) or (c = ?))
进行优化以在执行之前删除整个where子句(无论如何在DB2上,在您要求之前,构造在您需要删除where子句的效果但仍保持参数的情况下很有用占位符(使用带有Javascript的BIRT来修改通配符的查询))。
Derby还提供了用于检查所使用的实际查询计划的工具,因此您可以使用Derby运行实验并查看Derby选择的查询计划。您可以使用-Dderby.language.logQueryPlan = true运行Derby,Derby会将查询计划写入derby.log,或者您可以使用RUNTIMESTATISTICS工具,如下所述: http://db.apache.org/derby/docs/10.5/tuning/ctundepth853133.html
我不确定Derby是否会提前删除A LIKE'%',但我也不认为该子句的存在会导致执行速度大幅下降。
我非常有兴趣看到您在环境中获得的实际查询计划输出,包括和不包含A LIKE'%'条款。
Oracle 10gR2似乎没有针对这种情况执行特殊优化,但它确实认识到LIKE'%'排除了空值。
create table like_test (col1)
as select cast(dbms_random.string('U',10) as varchar2(10))
from dual
connect by level <= 1000
/
insert into like_test values (null)
/
commit
/
exec dbms_stats.gather_table_stats(user,'like_test')
explain plan for
select count(*)
from like_test
/
select plan_table_output from table(dbms_xplan.display)
/
explain plan for
select count(*)
from like_test
where col1 like '%'
/
select plan_table_output from table(dbms_xplan.display)
/
explain plan for
select count(*)
from like_test
where col1 is not null
/
select plan_table_output from table(dbms_xplan.display)
/
......给...
Plan hash value: 3733279756
------------------------------------------------------------------------
| Id | Operation | Name | Rows | Cost (%CPU)| Time |
------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | | |
| 2 | TABLE ACCESS FULL| LIKE_TEST | 1001 | 3 (0)| 00:00:01 |
------------------------------------------------------------------------
......和......
Plan hash value: 3733279756
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 10 | | |
|* 2 | TABLE ACCESS FULL| LIKE_TEST | 1000 | 10000 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("COL1" LIKE '%')
......和......
Plan hash value: 3733279756
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 10 | 3 (0)| 00:00:01 |
| 1 | SORT AGGREGATE | | 1 | 10 | | |
|* 2 | TABLE ACCESS FULL| LIKE_TEST | 1000 | 10000 | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter("COL1" IS NOT NULL)
注意TABLE ACCESS FULL行上的基数(行)
根据LIKE谓词的结构以及您正在测试的字段,您可能需要进行全表扫描。从语义上讲,'%'可能意味着全表扫描,但Sql Server会在内部对查询进行各种优化。所以问题就变成了:Sql Server是否在用'%'形成的LIKE谓词上进行优化并将其抛出WHERE子句?
一方面,我认为缺失的讨论是一个事实,即OP想要使用准备好的发言。当时的发言准备,该数据库/优化将不能够工作的简化,有人提到,因此不能优化掉的 a like '%'
作为实际价值不会知道在准备的时间。
因此:
- 当使用准备好的发言,有四种不同的报表可提供的(0,只有一个,只有b,二者)和使用适当的一个在需要的时候
- 看看你得到更好的效绩时不要使用准备好的发言时坚持只有一个声明(虽然它会很容易,不包括"空"的条件)
如果列的空值为空,该怎么办?您的查询可能与之匹配。
如果这是对真实世界应用程序的查询,请尝试使用大多数现代SQL数据库的自由文本索引功能。性能问题将变得微不足道。
一个简单的if语句 如果(A B) 搜索一个b 否则(A) 搜索一个 别的B. 搜索b 其他 告诉用户他们没有指定任何内容
很容易维护并且变得更容易理解,而不是对LIKE运算符做出假设。当您显示结果时,您可能会在UI中执行此操作“您搜索A找到x”或“您搜索A B找到......”
我不确定使用准备好的语句与您所描述的参数类型的价值。原因是您可能会欺骗查询优化器准备一个完全错误的执行计划,具体取决于哪个参数是'%'。
例如,如果使用A列上的索引使用执行计划准备语句,但A列的参数结果为'%',则可能会遇到性能不佳。
带有“或”的where子句比如'%'&quot;因为唯一的谓词将与no where子句完全相同。