[20150715]一条sql语句的优化.txt

简介: [20150715]一条sql语句的优化.txt --生产系统发现一条语句。 update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','') --第1眼看到的感觉真的很想骂人,什么能没有where条件呢? --我把这个表拷贝过来。

[20150715]一条sql语句的优化.txt

--生产系统发现一条语句。
update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','')

--第1眼看到的感觉真的很想骂人,什么能没有where条件呢?
--我把这个表拷贝过来。这个表占用1G多1点,在测试环境执行看看:

-- copy from system/xxxx@ip:1521/tyt create presc_check using select * from dmd.presc_check;

SCOTT@test> set autot traceonly
SCOTT@test> update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','')
4164454 rows updated.

Execution Plan
----------------------------------------------------------
Plan hash value: 1940686096

----------------------------------------------------------------------------------
| Id  | Operation          | Name        | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT   |             |  3670K|  7008M| 34762   (1)| 00:00:01 |
|   1 |  UPDATE            | PRESC_CHECK |       |       |            |          |
|   2 |   TABLE ACCESS FULL| PRESC_CHECK |  3670K|  7008M| 34762   (1)| 00:00:01 |
----------------------------------------------------------------------------------
Note
-----
   - dynamic sampling used for this statement (level=2)
Statistics
----------------------------------------------------------
       1104  recursive calls
    4301528  db block gets
     257057  consistent gets
     127892  physical reads
1278411184  redo size
        849  bytes sent via SQL*Net to client
        829  bytes received via SQL*Net from client
          3  SQL*Net roundtrips to/from client
          1  sorts (memory)
          0  sorts (disk)
    4164454  rows processed
--看看redo size=1278411184/1024/1024/1024=1.1906131953001223388 1.2G.

--删除表重新拷贝看看。

SCOTT@test> select count(*) from presc_check  where  diagnosisreplace(diagnosis,',慢性病drugs','') ;
  COUNT(*)
----------
         0

--可以发现没有1条是满足diagnosisreplace(diagnosis,',慢性病drugs',''),全部都是相等的。也许是我导出的时间,因为这个作业
--是晚上3:40分执行的。但是至少说明满足diagnosisreplace(diagnosis,',慢性病drugs','')条件的很少。

--开发至少应该写成这样:
update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','') where t.diagnosisreplace(t.diagnosis,',慢性病drugs','');

--但是这样依旧无法避开全表扫描。必须建立一个函数索引减少扫描的记录。利用instr函数就可以解决这个问题。
create index if_presc_check_diag on presc_check( instr(diagnosis,',慢性病drugs',1) );

SCOTT@test> select instr(diagnosis,',慢性病drugs',1) from presc_check where rownumINSTR(DIAGNOSIS,',慢性病DRUGS',1)
---------------------------------
                                0
                                0
                                0

--正常instr(diagnosis,',慢性病drugs',1)都是0,这样索引会包含大量0的数据,而这些是不需要的,仅仅需要保留大于0的信息,利用
--索引不保留null的特性。应该建立如下索引:

create index if_presc_check_diag on presc_check( decode(instr(diagnosis,',慢性病drugs',1),0,NULL,1));
--这样就可以保留diagnosisreplace(diagnosis,',慢性病drugs','')不等的记录。而且索引很小。

--最终修改语句改为:
update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','') where decode(instr(diagnosis,',慢性病drugs',1),0,NULL,1)=1;

--测试:
SCOTT@test> update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','') where decode(instr(diagnosis,',慢性病drugs',1),0,NULL,1)=1;
0 rows updated.


SCOTT@test> @dpc '' ''
PLAN_TABLE_OUTPUT
-----------------------------------------------------------------------------------------------
SQL_ID  0r2b2dphxpapc, child number 0
-------------------------------------
update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','')
where decode(instr(diagnosis,',慢性病drugs',1),0,NULL,1)=1
Plan hash value: 1940686096
-----------------------------------------------------------------------------------
| Id  | Operation          | Name        | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
-----------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT   |             |        |       | 34981 (100)|          |
|   1 |  UPDATE            | PRESC_CHECK |        |       |            |          |
|*  2 |   TABLE ACCESS FULL| PRESC_CHECK |  33816 |    64M| 34981   (1)| 00:00:01 |
-----------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - UPD$1
   2 - UPD$1 / T@UPD$1
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter(TO_NUMBER(DECODE(INSTR("DIAGNOSIS",',慢性病drugs',1),0,NULL,'1'))=1)
Note
-----
   - dynamic sampling used for this statement (level=2)
  
--奇怪还是没用索引。哦忘记分析表了,分析看看。

exec sys.dbms_stats.gather_table_stats ( OwnName => user,TabName => 'presc_check',Estimate_Percent => NULL,Method_Opt => 'FOR ALL COLUMNS SIZE 1 ',Cascade => True ,No_Invalidate => false)
--问题依旧。奇怪了。

--仔细看过滤条件:
   2 - filter(TO_NUMBER(DECODE(INSTR("DIAGNOSIS",',慢性病drugs',1),0,NULL,'1'))=1)

--什么会这样。

SCOTT@test> create index if_presc_check_diag on presc_check( to_number(decode(instr(diagnosis,',慢性病drugs',1),0,NULL,1)));
Index created.


SCOTT@test> update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','') where decode(instr(diagnosis,',慢性病drugs',1),0,NULL,1)=1;
0 rows updated.

SCOTT@test> @dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  0r2b2dphxpapc, child number 0
-------------------------------------
update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','')
where decode(instr(diagnosis,',慢性病drugs',1),0,NULL,1)=1
Plan hash value: 4008913632
-----------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
-----------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT             |                     |        |       |     1 (100)|          |
|   1 |  UPDATE                      | PRESC_CHECK         |        |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| PRESC_CHECK         |  41645 |  1260K|     1   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | IF_PRESC_CHECK_DIAG |      1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - UPD$1
   2 - UPD$1 / T@UPD$1
   3 - UPD$1 / T@UPD$1
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("T"."SYS_NC00070$"=1)

--实际上也可以建立这样的索引:

SCOTT@test> drop index  if_presc_check_diag ;
Index dropped.

SCOTT@test> create index if_presc_check_diag on presc_check( decode(instr(diagnosis,',慢性病drugs',1),0,NULL,'1'));
Index created.

SCOTT@test> update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','') where decode(instr(diagnosis,',慢性病drugs',1),0,NULL,'1')='1';
0 rows updated.

SCOTT@test> @dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  22ujr6zwy4asn, child number 0
-------------------------------------
update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','')
where decode(instr(diagnosis,',慢性病drugs',1),0,NULL,'1')='1'

Plan hash value: 4008913632

-----------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
-----------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT             |                     |        |       |     1 (100)|          |
|   1 |  UPDATE                      | PRESC_CHECK         |        |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| PRESC_CHECK         |  41645 |   813K|     1   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | IF_PRESC_CHECK_DIAG |      1 |       |     1   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - UPD$1
   2 - UPD$1 / T@UPD$1
   3 - UPD$1 / T@UPD$1
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("T"."SYS_NC00070$"='1')

--看来以后要注意这种情况的隐式转换。实际上问题出在decode(instr(diagnosis,',慢性病drugs',1),0,NULL,1)里面的NULL,oracle
--缺省认为是字符串类型null,而不是数字类型的null,改成如下:

create index if_presc_check_diagx on presc_check( decode(instr(diagnosis,',慢性病drugs',1),0,cast(NULL as number),1));

SCOTT@test> update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','') where decode(instr(diagnosis,',慢性病drugs',1),0,cast(NULL as number),1)=1;
0 rows updated.

SCOTT@test> @dpc '' ''
PLAN_TABLE_OUTPUT
-------------------------------------
SQL_ID  f5b0rzmyd2uzh, child number 0
-------------------------------------
update presc_check t set t.diagnosis=replace(t.diagnosis,',慢性病drugs','')
where decode(instr(diagnosis,',慢性病drugs',1),0,cast(NULL as number),1)=1
Plan hash value: 2418858926
------------------------------------------------------------------------------------------------------
| Id  | Operation                    | Name                 | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |
------------------------------------------------------------------------------------------------------
|   0 | UPDATE STATEMENT             |                      |        |       |     1 (100)|          |
|   1 |  UPDATE                      | PRESC_CHECK          |        |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| PRESC_CHECK          |  41645 |  1260K|     1   (0)| 00:00:01 |
|*  3 |    INDEX RANGE SCAN          | IF_PRESC_CHECK_DIAGX |      1 |       |     1   (0)| 00:00:01 |
------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
   1 - UPD$1
   2 - UPD$1 / T@UPD$1
   3 - UPD$1 / T@UPD$1
Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("T"."SYS_NC00071$"=1)

--当然应该选择这个索引更佳:
create index if_presc_check_diag on presc_check( decode(instr(diagnosis,',慢性病drugs',1),0,NULL,'1'));

--应该字符类型'1'仅仅占用1个字节,而数字1占用两个字节,并且从写法讲这样写decode(instr(diagnosis,',慢性病drugs',1),0,cast(NULL as number),1)=1不是很好。

目录
相关文章
|
12天前
|
SQL
慢sql治理问题之 Task 数量分布不均的问题你们是如何优化的
慢sql治理问题之 Task 数量分布不均的问题你们是如何优化的
慢sql治理问题之 Task 数量分布不均的问题你们是如何优化的
|
7天前
|
Java XML Maven
跨越时代的飞跃:Struts 2 升级秘籍——从旧版本无缝迁移到最新版,焕发应用新生!
【8月更文挑战第31天】随着软件技术的发展,Struts 2 框架也在不断更新。本文通过具体案例指导开发者如何从旧版平滑升级到 Struts 2.6.x。首先更新 `pom.xml` 中的依赖版本,并执行 `mvn clean install`。接着检查 `struts.xml` 配置,确保符合新版本要求,调整包扫描器等设置。审查 Action 类及其注解,检查配置文件中的弃用项及插件。更新自定义拦截器实现,并验证日志配置。最后,通过一系列测试确保升级后的系统正常运行。通过这些步骤,可以顺利完成 Struts 2 的版本升级,提升应用的安全性和性能。
24 0
|
7天前
|
SQL 存储 数据库
|
7天前
|
SQL 数据管理 关系型数据库
SQL与云计算:利用云数据库服务实现高效数据管理——探索云端SQL应用、性能优化、安全性与成本效益,为企业数字化转型提供全方位支持
【8月更文挑战第31天】在数字化转型中,企业对高效数据管理的需求日益增长。传统本地数据库存在局限,而云数据库服务凭借自动扩展、高可用性和按需付费等优势,成为现代数据管理的新选择。本文探讨如何利用SQL和云数据库服务(如Amazon RDS、Google Cloud SQL和Azure SQL Database)实现高效的数据管理。通过示例和最佳实践,展示SQL在云端的应用、性能优化、安全性及成本效益,助力企业提升竞争力。
22 0
|
7天前
|
SQL 关系型数据库 MySQL
SQL索引构建与优化的神奇之处:如何用高效索引让你的数据检索飞起来?
【8月更文挑战第31天】在现代软件开发中,数据库索引对于提升查询性能至关重要。本文详细介绍了SQL索引的概念、构建方法及优化技巧,包括避免不必要的索引、使用复合索引等策略,并提供了实用的示例代码,如 `CREATE INDEX index_name ON table_name (column_name, another_column_name);`。通过遵循这些最佳实践,如了解查询模式和定期维护索引,可以大幅提高数据检索效率,从而增强应用程序的整体性能。
29 0
|
7天前
|
SQL 关系型数据库 MySQL
OceanBase 的 SQL 兼容性与优化
【8月更文第31天】随着分布式计算的发展,越来越多的企业开始采用分布式数据库来满足其大规模数据存储和处理的需求。OceanBase 作为一款高性能的分布式关系数据库,其设计旨在为用户提供与传统单机数据库类似的 SQL 查询体验,同时保持高可用性和水平扩展能力。本文将深入探讨 OceanBase 的 SQL 引擎特性、兼容性问题,并提供一些针对特定查询进行优化的方法和代码示例。
20 0
|
12天前
|
SQL 资源调度 流计算
慢sql治理问题之在 Flink 中, userjar 分发问题如何优化
慢sql治理问题之在 Flink 中, userjar 分发问题如何优化
|
2月前
|
SQL 存储 监控
SQL Server的并行实施如何优化?
【7月更文挑战第23天】SQL Server的并行实施如何优化?
52 13
|
2月前
|
SQL
解锁 SQL Server 2022的时间序列数据功能
【7月更文挑战第14天】要解锁SQL Server 2022的时间序列数据功能,可使用`generate_series`函数生成整数序列,例如:`SELECT value FROM generate_series(1, 10)。此外,`date_bucket`函数能按指定间隔(如周)对日期时间值分组,这些工具结合窗口函数和其他时间日期函数,能高效处理和分析时间序列数据。更多信息请参考官方文档和技术资料。
|
2月前
|
SQL 存储 网络安全
关系数据库SQLserver 安装 SQL Server
【7月更文挑战第26天】
43 6
下一篇
DDNS