`
housheng33
  • 浏览: 239179 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

sql like 优化

    博客分类:
  • sql
 
阅读更多
A:
最多使用ffs,其他没有什么好方法!
两边都有%,就不会走index了。。
如果表不是很大,可以考虑keep之。。

B:
这个问题首先是在TAOBAO DBA的BLOG上看到丹臣写的关于Like和INSTR的性能问题。不过他只是给出了结果。我对这个函数性能感到有趣,之前一直没有关注过,遂自己详细测试了下。

Oracle 9208:

SQL> select count(*) from item;

COUNT(*)

----------

2781806

SQL> select count(*) from item where item like '%A0';

COUNT(*)

----------

9036

Elapsed: 00:00:04.03

Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1134 Card=1 Bytes=16

)

1 0 SORT (AGGREGATE)

2 1 INDEX (FAST FULL SCAN) OF 'PK_ITEM' (UNIQUE) (Cost=1134

Card=138698 Bytes=2219168)

Statistics

----------------------------------------------------------

0 recursive calls

0 db block gets

10369 consistent gets

0 physical reads

0 redo size

519 bytes sent via SQL*Net to client

656 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed

可以看到走了FFS, 10396 Consistent Gets, Elapsed tail=4.03

再看SUBSTR

SQL> select count(*) from item where substr(item,-2)='A0';

COUNT(*)

----------

9036

Elapsed: 00:00:00.84

Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=1134 Card=1 Bytes=16

)

1 0 SORT (AGGREGATE)

2 1 INDEX (FAST FULL SCAN) OF 'PK_ITEM' (UNIQUE) (Cost=1134

Card=27740 Bytes=443840)

Statistics

----------------------------------------------------------

0 recursive calls

0 db block gets

10369 consistent gets

0 physical reads

0 redo size

519 bytes sent via SQL*Net to client

656 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed

可以看到PLAN一样,Consistent Gets一样,Elapsed tail=0.84

SUBSTR的耗时只有LIKE的21%左右,鉴于PLAN和Consistent Gets一致,所以可以认为是SUBSTR的CPU Cost要小于LIKE。

NOT LIKE的情况和LIKE相似。

INSTR的情况也如SUBSTR

确实如丹臣所言,Oracle的函数有相当的优化。

但9i的Optimizer在计算Cost的时候是以IO为准,那么在以CPU为准的10G上呢,Cost会有什么差别?

下面在10203上测试

SQL> select count(*) from item where item like '%A0';

COUNT(*)

----------

9104

Elapsed: 00:00:03.03

Execution Plan

----------------------------------------------------------

Plan hash value: 642095792

--------------------------------------------------------------------------------

-

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time

|

--------------------------------------------------------------------------------

-

| 0 | SELECT STATEMENT | | 1 | 15 | 2211 (3)| 00:00:27

|

| 1 | SORT AGGREGATE | | 1 | 15 | |

|

|* 2 | INDEX FAST FULL SCAN| PK_ITEM | 139K| 2037K| 2211 (3)| 00:00:27

|

--------------------------------------------------------------------------------

-

Predicate Information (identified by operation id):

---------------------------------------------------

2 - filter("ITEM" LIKE '%A0')

Statistics

----------------------------------------------------------

0 recursive calls

0 db block gets

10117 consistent gets

0 physical reads

0 redo size

516 bytes sent via SQL*Net to client

492 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed

SQL> select count(*) from item where substr(item,-2)='A0';

COUNT(*)

----------

9104

Elapsed: 00:00:01.24

Execution Plan

----------------------------------------------------------

Plan hash value: 642095792

--------------------------------------------------------------------------------

-

| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time

|

----------------------------------------------------------------------

-

| 0 | SELECT STATEMENT | | 1 | 15 | 2220 (3)| 00:00:27

|

| 1 | SORT AGGREGATE | | 1 | 15 | |

|

|* 2 | INDEX FAST FULL SCAN| PK_ITEM | 27819 | 407K| 2220 (3)| 00:00:27

|

--------------------------------------------------------------------------------

-

Predicate Information (identified by operation id):

---------------------------------------------------

2 - filter(SUBSTR("ITEM",-2)='A0')

Statistics

----------------------------------------------------------

0 recursive calls

0 db block gets

10117 consistent gets

0 physical reads

0 redo size

516 bytes sent via SQL*Net to client

492 bytes received via SQL*Net from client

2 SQL*Net roundtrips to/from client

0 sorts (memory)

0 sorts (disk)

1 rows processed

结果是SUBSTR-2220-elapsed 1.24,Like-2211-elapsed 3.03。

显然SUBSTR在CPU占用上要高那么一点, 但是其相对于Like仅 41% 的耗时,使得它完全可以取代Like在查询以XX结尾的SQL中的地位。

BTW,我在一台Idle Server上的测试表明,使用SUBSTR不仅在耗时上缩短,而且CPU使用率也较LIKE低(9.5%/12.5%)

类似的测试表明INSTR相对LIKE ‘%XX%’的优势。

(函数取代LIKE ‘XX%’就别想了,一个Index Range Scan相对FFS的优势太大了)


C:
SQL> select count(*) from t;

  COUNT(*)
----------
     51838
SQL> insert /*+append*/ into t select * from t;
已创建51838行。
SQL> commit;
提交完成。
SQL> insert /*+append*/ into t select * from t;
已创建103676行。
SQL> commit;
提交完成。
SQL> insert /*+append*/ into t select * from t;
已创建207352行。
SQL> commit;
提交完成。
SQL> insert /*+append*/ into t select * from t;
已创建414704行。
SQL> commit;
提交完成。
SQL> select count(*) from t;

  COUNT(*)
----------
    829408
SQL> set autot traceonly exp stat
SQL> select * from t where object_type like '%TYPE%';

已选择34064行。

执行计划
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  2592 |   235K|   160   (2)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| T    |  2592 |   235K|   160   (2)| 00:00:02 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("OBJECT_TYPE" LIKE '%TYPE%')

统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      13623  consistent gets
      11364  physical reads
          0  redo size
    1466572  bytes sent via SQL*Net to client
      25370  bytes received via SQL*Net from client
       2272  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      34064  rows processed
SQL> SQL> select /*+index(t,t_idx)*/ * from t where object_type like '%TYPE%';

已选择34064行。

执行计划
----------------------------------------------------------
Plan hash value: 3778778741
-------------------------------------------------------------------------------------
| Id  | Operation                   | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |       |  2592 |   235K|   260   (2)| 00:00:04 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T     |  2592 |   235K|   260   (2)| 00:00:04 |
|*  2 |   INDEX FULL SCAN           | T_IDX |  2592 |       |   146   (2)| 00:00:02 |
-------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("OBJECT_TYPE" LIKE '%TYPE%')

统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      14131  consistent gets
       1982  physical reads
     290188  redo size
    1477872  bytes sent via SQL*Net to client
      25370  bytes received via SQL*Net from client
       2272  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      34064  rows processed
SQL> SQL>
SQL>
SQL>
SQL> select * from t where instr(object_type,'TYPE')>0;

已选择34064行。

执行计划
----------------------------------------------------------
Plan hash value: 1601196873
--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  2592 |   235K|   161   (3)| 00:00:02 |
|*  1 |  TABLE ACCESS FULL| T    |  2592 |   235K|   161   (3)| 00:00:02 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter(INSTR("OBJECT_TYPE",'TYPE')>0)

统计信息
----------------------------------------------------------
          0  recursive calls
          0  db block gets
      13623  consistent gets
       9952  physical reads
          0  redo size
    1466572  bytes sent via SQL*Net to client
      25370  bytes received via SQL*Net from client
       2272  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      34064  rows processed
SQL> SQL> SELECT * from t where rowid in(select /*+index_ffs(t,t_idx)*/ rowid from t where object_type like '%TYPE%');
已选择34064行。

执行计划
----------------------------------------------------------
Plan hash value: 628352769
-------------------------------------------------------------------------------
| Id  | Operation             | Name  | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |       |  2592 |   288K|   197   (4)| 00:00:03 |
|*  1 |  HASH JOIN            |       |  2592 |   288K|   197   (4)| 00:00:03 |
|*  2 |   INDEX FAST FULL SCAN| T_IDX |  2592 | 54432 |    35   (6)| 00:00:01 |
|   3 |   TABLE ACCESS FULL   | T     | 51838 |  4707K|   161   (3)| 00:00:02 |
-------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   1 - access(ROWID=ROWID)
   2 - filter("OBJECT_TYPE" LIKE '%TYPE%')

统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
      17559  consistent gets
       9991  physical reads
          0  redo size
    1466572  bytes sent via SQL*Net to client
      25370  bytes received via SQL*Net from client
       2272  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      34064  rows processed



小结:

   1,目前看instr比rowid及全表报描的性能更高及index_ffs更高

    2,index_ffs虽强制走了索引,但成本最高

D:
free介绍的是一种方法;RudolfLu曾经也介绍过一种方法,就是根据搜索字段+rowid建立一个物理表,对这个物理表进行全表,相较ffs会更快一些,不过需要定期刷新物理表,适用于变化较少,查询要求实时性要求不高的环境。

其实也可以用Oracle的全文检索技术,可能会有更好的结果,看我以下的一个例子:

[php]

1.这是模糊查询的结果
SQL> select count(*) from jivemessage where subject like '%abc%';

  COUNT(*)
----------
        13

Elapsed: 00:00:15.31

2.这是全文检索的结果
SQL> select count(*) from jivemessage where contains(subject,'abc')>0;

  COUNT(*)
----------
        25

Elapsed: 00:00:00.03

3.模糊查询的内容
SQL> select subject from jivemessage where subject like '%abc%';

SUBJECT
--------------------------------------------------------------------------------
abc
测试发贴""abc
abc
Re: abc
Re: abc
Re: abc
<testabcde>
初夜abc
abcd
abc
abc

SUBJECT
--------------------------------------------------------------------------------
哈哇abc
http;//baoxing.168abc.com

13 rows selected.

Elapsed: 00:00:03.29

4.也许这是我们更想要的结果
SQL> select subject from jivemessage where contains(subject,'abc')>0;

SUBJECT
--------------------------------------------------------------------------------
【游戏】 把你的名字的首字母用智能ABC打出,看能出来什么?
游戏——把你的名字首字母用智能ABC打出来
智能ABC暗藏杀机
ABC
ABC
ABC
ABC
ABC
ABC
哈哇abc
abc

SUBJECT
--------------------------------------------------------------------------------
abc
ABC
振奋爱的激情方案ABC
智能ABC的错吗?
ABC全选
瓜果美容ABC
经典英文歌曲ABC,不好你拿版砖砍我,好就回帖顶一下!
初夜abc
Re: abc
Re: abc
Re: abc

SUBJECT
--------------------------------------------------------------------------------
abc
测试发贴""abc
abc

25 rows selected.

Elapsed: 00:00:00.04

D:
select * from foo where rowid in (select /*+index_ffs(foo ind_name) */rowid from foo where name like '%ddd%' )

e:
SELECT
       org.*
  FROM test_ffs org, (SELECT /*+no_merge index_ffs(test_ffs  object_name ) */
                             ROWID AS r, object_name
                        FROM test_ffs
                       WHERE object_name LIKE '%A%' ) tmp
WHERE org.ROWID = tmp.r ;
INDEX_FFS(table  index_name)所查询的列必须全部被索引才可使用


f:
1。eygle 的 全文检索法:
对于用于条件的column length 占TABLE的record length的大部分的,速度应该是最快的。如果用于条件的column length 占TABLE的record length的比例并不是很大,那样优势就不明显,毕竟要多安装和管理一个组件。

2。RudolfLu的新表法
和上面对应的是,如果用于条件的column length 占TABLE的record length的比例并不是很大,比较好用,如果用于条件的column length 占TABLE的record length的大部分的话,那就没什么用了,另外,要多维护一个table,还要考虑两个表同步的问题,不建议使用。

3。我的index_ffs + rowid 法
主要优劣势和 RudolfLu的新表法 接近,但是index可以自动更新。而且,在某种环境里,可能已经有相关的index,可能并不需要增加新的index.
另外,没做过测试,不知道相同数据量的index_ffs  和 FTS 性能区别。


g:
1、尽量不要使用 like '%..%'

2、对于 like '..%..' (不以 % 开头),Oracle可以应用 colunm上的index

3、对于 like '%...' 的 (不以 % 结尾),可以利用 reverse + function index 的形式,变化成 like '..%' 代码



建测试表和Index。

注意:重点在于带reverse的function index。同时,一定要使用CBO才行......



SQL> select reverse('123') from dual;

REVERSE('123')

--------------------------------

321

1 row selected.



SQL> create table test_like as select object_id,object_name from dba_objects;

Table created.



SQL> create index test_like__name on test_like(object_name);

Index created.



SQL> create index test_like__name_reverse on test_like(reverse(object_name));

Index created.



SQL> analyze table test_like compute statistics for table for all indexes;

Table analyzed.



SQL> set autot trace



--常量开头的like , 会利用index ,没问题......

SQL> select * from test_like where object_name like AS%';

Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=655 Bytes=15720)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TEST_LIKE' (Cost=2 Card=655Bytes=15720)

2 1 INDEX (RANGE SCAN) OF 'TEST_LIKE__NAME' (NON-UNIQUE) (Cost=2 Card=118)



-- 开头和结尾都是%,对不起,很难优化



SQL> select * from test_like where object_name like '%%';



Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=655 Bytes=15720)

1 0 TABLE ACCESS (FULL) OF 'TEST_LIKE' (Cost=6 Card=655 ytes=15720)



-- 以常量结束,直接写的时候是不能应用index的

SQL> select * from test_like where object_name like '%S';

Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=655 Bytes=15720)

1 0 TABLE ACCESS (FULL) OF 'TEST_LIKE' (Cost=6 Card=655 Bytes=15720)



--'以常量结束的,加个reverse 函数,又可以用上index了'

SQL> select * from test_like where reverse(object_name)like reverse('%AS');

Execution Plan

----------------------------------------------------------

0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=655 Bytes=15720)

1 0 TABLE ACCESS (BY INDEX ROWID) OF 'TEST_LIKE' (Cost=2 Card=655 Bytes=15720)

2 1 INDEX (RANGE SCAN) OF 'TEST_LIKE__NAME_REVERSE' (NON-UNIQUE) (Cost=2 Card=118)
分享到:
评论

相关推荐

    OracleSQL的优化.pdf

    Oracle SQL 优化 Oracle SQL 优化是数据库性能优化的关键部分。为了提高数据库的性能,我们需要从五个方面进行调整:去掉不必要的大型表的全表扫描、缓存小型表的全表扫描、检验优化索引的使用、检验优化的连接技术...

    mysql数据库sql优化

    ### MySQL数据库SQL优化 #### 一、SQL优化 在MySQL数据库管理中,SQL查询的性能直接影响到系统的响应时间和资源消耗。通过合理的SQL优化,可以显著提高数据处理速度,降低服务器负载,提升用户体验。 ##### 1.1 ...

    sqlserver优化笔记

    ### SQL Server 优化知识点 #### 一、SQL性能优化技巧 **1.1 查询的模糊匹配** - **问题描述**:使用 `LIKE '%parm1%'` 的查询方式会导致索引失效,降低查询效率。 - **解决方案**: - **前端改进**:改变用户...

    SQL优化 '%5400%' LIKE操作符

    ### SQL优化 '%5400%' LIKE操作符 在数据库查询优化中,SQL语句的编写方式对于查询性能有着至关重要的影响。本文将基于提供的标题、描述和部分内容,深入探讨几种常用的SQL优化策略以及特定场景下的优化技巧。 ###...

    sql语句优化建议

    - **操作符优化**:优化器会尝试将某些操作符(如`LIKE`、`IN`)转换为更高效的形式,比如将`ename LIKE 'SMITH'`转换为`ename = 'SMITH'`,或者将`IN`列表转换为一系列`OR`语句。然而,这种转换依赖于字段类型和...

    SQL Server SQL优化

    ### SQL Server SQL优化 #### 一、SQL优化的重要性与原则 在SQL Server的实际运行过程中,随着数据量的增长和用户访问频率的提升,数据库性能问题逐渐显现。根据所谓的“二八法则”,即大约20%的慢查询消耗了系统...

    sql语句优化原则

    SQL语句优化原则是数据库管理和应用开发中的关键环节,它涉及到如何提高查询效率,减少资源消耗,提升系统整体性能。以下是一些针对SQL语句优化的重要原则和方法: 1. **利用索引**:索引是提高查询速度的关键。...

    sql书写优化和性能优化

    ### SQL书写优化与性能优化详解 #### 一、书写风格 **1. SQL语句全部使用小写** 为了保持代码一致性与可读性,所有SQL语句均需使用小写字母编写。这一规则适用于所有的关键字、函数名称及操作符等。 **2. 引用...

    SQL语句优化数据库java

    ### SQL语句优化数据库Java #### 标题与描述中的知识点概述 在标题“SQL语句优化数据库Java”中,我们可以看出文章主要讨论的是如何通过优化SQL语句来提高数据库性能,尤其是对于Java应用程序而言。描述部分则...

    Sql优化.ppt

    SQL 查询优化是数据库优化的重要部分,查询优化器是 SQL SERVER 中的一个组件,可以自动优化查询语句,提高查询效率。本文将详细介绍查询优化器的工作原理、SARG 的定义和应用、查询优化的 tips 等。 一、查询优化...

    SQL语句优化原则.pdf

    在数据库系统中,SQL语句的优化是确保系统性能稳定、响应快速的关键环节。在大规模数据环境下,SQL语句可能消耗掉70%至90%的数据库资源,因此,劣质的SQL语句和优质SQL语句之间的性能差距可高达百倍。优化的目标是在...

    SQL优化.pdf

    SQL优化规则_01_Alias相关: 别名使用规则是SQL优化中非常基础但又非常重要的一个方面。首先,建议使用AS关键字来显示声明列或表的别名。在SQL语句中,使用AS关键字可以使别名的定义更加明确,减少歧义,使得SQL语句...

    Oracle SQL语句优化技术分析

    ### Oracle SQL语句优化技术分析 #### 概述 Oracle SQL语句优化是数据库管理中的一个重要环节,通过优化SQL语句可以显著提升系统的响应速度、提高数据库资源的利用率以及改善用户体验。本文将从多个角度出发,详细...

    sql语句的优化

    ### SQL语句优化详解 #### 一、引言 在数据库设计与管理中,SQL语句的优化是一项至关重要的工作。合理的SQL优化不仅能显著提升数据处理速度,还能有效降低服务器资源消耗,从而提高整个系统的响应时间和用户体验。...

    ORACLE SQL 优化 存储过程 PROCEDURE

    文章首先介绍了基本的 SQL 语句,包括 LEFT JOIN 和 INNER JOIN 的区别、LIKE 和 NOT LIKE 的模糊查询、DECODE 函数的使用、CASE WHEN THEN 语句的应用、字符串拼接的方法、日期函数 TO_DATE 和 TO_CHAR 的使用、...

    sql语句优化之降龙十八掌

    在数据库管理中,SQL语句优化是提升系统性能的关键步骤,尤其对于大型系统而言,一个高效的SQL查询可以显著减少响应时间,改善用户体验。本文将详细阐述"sql语句优化之降龙十八掌",逐一解析这十八个优化技巧,帮助...

    oracle like 的优化

    针对上述问题,本文将详细介绍几种有效的LIKE优化方法。 ##### 1. 避免使用 `LIKE '%%'` **问题分析**:当LIKE语句中的模式包含前导“%”,如`LIKE '%XYZ%'`时,Oracle数据库很难直接利用索引来加速查询过程。这是...

    Sql语句优化(很好的资料)

    SQL语句优化是提高软件系统效率的关键技术,尤其是在大数据量的场景下,高效的SQL能够显著提升数据库查询速度,降低系统资源消耗。以下是一些关于SQL优化的重要知识点: 1. **IN操作符**: - 使用IN操作符虽然使得...

    PostgreSQL Like模糊查询优化方案

    在SQL中,LIKE '%xxx%'这样的查询意味着我们需要查找包含特定字符串"xxx"的所有记录,不论该字符串出现在字段的哪个位置。由于%"xxx"%前后都有通配符,传统的B树索引无法直接帮助查询,因为它们是为顺序查找设计的,...

    sql 优化汇总 优化汇总 优化汇总

    SQL 优化是一个复杂而关键的任务,它涉及到数据库的性能、资源利用率和响应时间。以下是对标题和描述中提到的知识点的详细解释: 1. **没有索引或未使用索引**:索引是提高查询效率的关键,如果没有为常用查询条件...

Global site tag (gtag.js) - Google Analytics