查询中让优化器使用复合索引

简介:
-- Create table
create table MT_BIZ
(
  HOSPITAL_ID      VARCHAR2(20) not null,
  SERIAL_NO        VARCHAR2(16) not null,
  FEE_BATCH        NUMBER(5) default 1 not null,
  CASE_ID          NUMBER(12),
  BIZ_TYPE         VARCHAR2(2) not null,
  ORDINAL_NO       NUMBER(2) default 0 not null,
  DISTRICT_CODE    VARCHAR2(6),
  INDI_ID          NUMBER(12) not null,
  NAME             VARCHAR2(20) not null,
  SEX              CHAR(1) not null,
  PERS_TYPE        VARCHAR2(3) not null,
  OFFICE_GRADE     VARCHAR2(3) default '000' not null,
  IDCARD           VARCHAR2(25),
  IC_NO            VARCHAR2(25),
  BIRTHDAY         DATE,
  TELEPHONE        VARCHAR2(30),
  CORP_ID          NUMBER(10) not null,
  CORP_NAME        VARCHAR2(70) not null,
  TREATMENT_TYPE   VARCHAR2(3) not null,
  BIZ_TIMES        NUMBER(3),
  RELA_HOSP_ID     VARCHAR2(20),
  RELA_SERIAL_NO   VARCHAR2(16),
  SERIAL_APPLY     NUMBER(12),
  REG_DATE         DATE not null,
  REG_STAFF        VARCHAR2(8) not null,
  REG_MAN          VARCHAR2(20),
  REG_FLAG         CHAR(1) default '0' not null,
  BEGIN_DATE       DATE not null,
  REG_INFO         VARCHAR2(10),
  IN_DEPT          VARCHAR2(10),
  IN_DEPT_NAME     VARCHAR2(20),
  IN_AREA          VARCHAR2(10),
  IN_AREA_NAME     VARCHAR2(20),
  IN_BED           VARCHAR2(10),
  BED_TYPE         CHAR(1),
  PATIENT_ID       VARCHAR2(20),
  IN_DISEASE       VARCHAR2(20) not null,
  FOREGIFT         NUMBER(10,2),
  DIAGNOSE_DATE    DATE,
  DIAGNOSE         VARCHAR2(20),
  IN_DAYS          NUMBER(4),
  FIN_DISEASE      VARCHAR2(20),
  END_DATE         DATE,
  END_STAFF        VARCHAR2(8),
  END_MAN          VARCHAR2(30),
  FIN_INFO         VARCHAR2(10),
  IC_FLAG          CHAR(1) default '0' not null,
  REIMBURSE_FLAG   CHAR(1) default '0' not null,
  BIZ_END_DATE     DATE,
  FINISH_FLAG      CHAR(1) default '0' not null,
  POS_CODE         VARCHAR2(10),
  LOCK_FLAG        CHAR(1) default '0' not null,
  INJURY_BORTH_SN  NUMBER(12),
  REMARK           VARCHAR2(500),
  TRANS_FLAG       CHAR(1) default '0' not null,
  CENTER_ID        VARCHAR2(100) default 0 not null,
  PERS_TYPE_DETAIL VARCHAR2(3),
  CORP_TYPE_CODE   VARCHAR2(3),
  SPECIAL_CODE     VARCHAR2(3),
  DOCTOR_NO        VARCHAR2(20),
  DOCTOR_NAME      VARCHAR2(20),
  FIN_DISEASE1     VARCHAR2(20),
  FIN_DISEASE2     VARCHAR2(20),
  CASE_INFO        VARCHAR2(100),
  BILL_NO          VARCHAR2(20),
  HOS_SERIAL       VARCHAR2(30),
  DISEASE_TYPE     CHAR(1),
  DISEASE_FLAG     CHAR(1) default '0',
  RECUR_FLAG       CHAR(1) default '0',
  INJURY_TYPE      VARCHAR2(2) default '01'
);
-- Add comments to the table
comment on table MT_BIZ
  is '医疗业务表';
-- Add comments to the columns
comment on column MT_BIZ.HOSPITAL_ID
  is '医疗机构编号';
comment on column MT_BIZ.SERIAL_NO
  is '业务序列号';
comment on column MT_BIZ.FEE_BATCH
  is '费用批次';
comment on column MT_BIZ.CASE_ID
  is '病例分型序号';
comment on column MT_BIZ.BIZ_TYPE
  is '业务类别编号';
comment on column MT_BIZ.ORDINAL_NO
  is '内部序数';
comment on column MT_BIZ.DISTRICT_CODE
  is '社区编码(指个人所属行政区编码)';
comment on column MT_BIZ.INDI_ID
  is '个人编号';
comment on column MT_BIZ.NAME
  is '姓名';
comment on column MT_BIZ.SEX
  is '性别';
comment on column MT_BIZ.PERS_TYPE
  is '人员类别待遇代码';
comment on column MT_BIZ.OFFICE_GRADE
  is '公务员级别';
comment on column MT_BIZ.IDCARD
  is '公民身份号码';
comment on column MT_BIZ.IC_NO
  is 'IC卡号';
comment on column MT_BIZ.BIRTHDAY
  is '出生日期';
comment on column MT_BIZ.TELEPHONE
  is '联系电话';
comment on column MT_BIZ.CORP_ID
  is '单位编码';
comment on column MT_BIZ.CORP_NAME
  is '单位名称';
comment on column MT_BIZ.TREATMENT_TYPE
  is '待遇类别(用于区分同一业务类型的不同情况,比如生育门诊的三个月以上和三个月以上流产,不区分时为0)';
comment on column MT_BIZ.BIZ_TIMES
  is '本年业务次数';
comment on column MT_BIZ.RELA_HOSP_ID
  is '关联医疗机构编码';
comment on column MT_BIZ.RELA_SERIAL_NO
  is '关联业务序列号';
comment on column MT_BIZ.SERIAL_APPLY
  is '申请序列号';
comment on column MT_BIZ.REG_DATE
  is '业务登记日期';
comment on column MT_BIZ.REG_STAFF
  is '登记人工号';
comment on column MT_BIZ.REG_MAN
  is '登记人';
comment on column MT_BIZ.REG_FLAG
  is '登记标志(0:正常 1:转院 2:二次返院(审批通过后RELA_SERIAL_NO为空) 3:急诊留观转住院 4:90天或180天结算(处理后RELA_HOSP_ID为空,RELA_SERIAL_NO不为空))';
comment on column MT_BIZ.BEGIN_DATE
  is '业务开始时间';
comment on column MT_BIZ.REG_INFO
  is '业务开始情况(FR:提取冻结费用的零报业务  MW:医疗转工伤的零报业务)';
comment on column MT_BIZ.IN_DEPT
  is '入院科室';
comment on column MT_BIZ.IN_DEPT_NAME
  is '入院科室名称';
comment on column MT_BIZ.IN_AREA
  is '入院病区';
comment on column MT_BIZ.IN_AREA_NAME
  is '入院病区名称';
comment on column MT_BIZ.IN_BED
  is '入院床位号';
comment on column MT_BIZ.BED_TYPE
  is '床位类型';
comment on column MT_BIZ.PATIENT_ID
  is '医院业务号';
comment on column MT_BIZ.IN_DISEASE
  is '入院疾病诊断';
comment on column MT_BIZ.FOREGIFT
  is '预付款总额';
comment on column MT_BIZ.DIAGNOSE_DATE
  is '确诊日期';
comment on column MT_BIZ.DIAGNOSE
  is '确诊疾病诊断';
comment on column MT_BIZ.IN_DAYS
  is '住院天数';
comment on column MT_BIZ.FIN_DISEASE
  is '出院疾病诊断';
comment on column MT_BIZ.END_DATE
  is '业务终结日期';
comment on column MT_BIZ.END_STAFF
  is '终结人工号';
comment on column MT_BIZ.END_MAN
  is '终结人';
comment on column MT_BIZ.FIN_INFO
  is '业务终结情况';
comment on column MT_BIZ.IC_FLAG
  is '用卡标志';
comment on column MT_BIZ.REIMBURSE_FLAG
  is '中心报帐标志';
comment on column MT_BIZ.BIZ_END_DATE
  is '诊次结束时间';
comment on column MT_BIZ.FINISH_FLAG
  is '完成标志';
comment on column MT_BIZ.POS_CODE
  is 'POS机编号';
comment on column MT_BIZ.LOCK_FLAG
  is '锁定标志';
comment on column MT_BIZ.INJURY_BORTH_SN
  is '对应的工伤生育业务号';
comment on column MT_BIZ.REMARK
  is '备注';
comment on column MT_BIZ.TRANS_FLAG
  is '传输标志(0:未传输 1:已成功传输 2:未成功传输)';
comment on column MT_BIZ.CENTER_ID
  is '医保中心编码';
comment on column MT_BIZ.PERS_TYPE_DETAIL
  is '人员类别详细代码(bs_person.PERS_TYPE)';
comment on column MT_BIZ.CORP_TYPE_CODE
  is '单位类型';
comment on column MT_BIZ.SPECIAL_CODE
  is '特殊人群编码';
comment on column MT_BIZ.DOCTOR_NO
  is '医生编号';
comment on column MT_BIZ.DOCTOR_NAME
  is '医生姓名';
comment on column MT_BIZ.FIN_DISEASE1
  is '第一副诊断';
comment on column MT_BIZ.FIN_DISEASE2
  is '第二副诊断';
comment on column MT_BIZ.CASE_INFO
  is '病历信息';
comment on column MT_BIZ.BILL_NO
  is '单据号';
comment on column MT_BIZ.HOS_SERIAL
  is '医院交易流水号';
comment on column MT_BIZ.DISEASE_TYPE
  is '病种分型(A:病种单纯 B:严重 C:严重并发 D:危重)';
comment on column MT_BIZ.DISEASE_FLAG
  is '职业病标志(0 不是职业病,1 是职业病)';
comment on column MT_BIZ.RECUR_FLAG
  is '工伤复发标志(0 不是工伤复发,1 是工伤复发)';
comment on column MT_BIZ.INJURY_TYPE
  is '工伤类别(01:新工伤,02老工伤,对应新增wi_injury_type码表)';
-- Create/Recreate primary, unique and foreign key constraints
alter table MT_BIZ
  add constraint PK_MT_BIZ primary key (HOSPITAL_ID, SERIAL_NO)
  using index;
-- Create/Recreate indexes
create index IDX_MT_BIZ_BEGIN_DATE on MT_BIZ (BEGIN_DATE);
create index IDX_MT_BIZ_BIZ_END_DATE on MT_BIZ (BIZ_END_DATE);
create index IDX_MT_BIZ_CORP_ID on MT_BIZ (CORP_ID);
create index IDX_MT_BIZ_IB on MT_BIZ (INJURY_BORTH_SN);
create index IDX_MT_BIZ_INDI_ID on MT_BIZ (INDI_ID);
create index IDX_MT_BIZ_RELA on MT_BIZ (RELA_HOSP_ID, RELA_SERIAL_NO);

在mt_biz表中有一个复合主键是由hospital_id与serial_no组成的
其中serial_no是唯一值是由序列生成的,所以在查询数据时有些语句只使用serial_no
造成了使用不上索引的问题
因为如果索引是建立在多个列上, 只有在它的第一个列也叫前导列(leading
column)被where子句引用时,优化器才会选择使用该索引.
例如,不使用合主键的唯一索引中的前导列hospital_id时的语句执行计划如下
SQL> set autotrace traceonly;
SQL> select * from mt_biz a where a.serial_no='15485197';


执行计划
----------------------------------------------------------
Plan hash value: 3513793642

----------------------------------------------------------------------------
| Id  | Operation         | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |        |     1 |   244 |    42   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| MT_BIZ |     1 |   244 |    42   (0)| 00:00:01 |
----------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("A"."SERIAL_NO"='15485197')


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        190  consistent gets
          0  physical reads
          0  redo size
       2852  bytes sent via SQL*Net to client
        239  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
从显示的执行计划可以看出当没有使用复合索引中的前导列hospital_id时
是执行的全表扫描

当使用复合索引中的前导列hospital_id时
SQL> select * from mt_biz a where a.hospital_id='4307000009';

已选择348行。


执行计划
----------------------------------------------------------
Plan hash value: 3033165289

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

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

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

|   0 | SELECT STATEMENT            |           |    18 |  4392 |     8   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| MT_BIZ    |    18 |  4392 |     8   (0)| 00:00:01 |

|*  2 |   INDEX RANGE SCAN          | PK_MT_BIZ |    18 |       |     1   (0)| 00:00:01 |

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


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("A"."HOSPITAL_ID"='4307000009')


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        345  consistent gets
          0  physical reads
          0  redo size
     102775  bytes sent via SQL*Net to client
        400  bytes received via SQL*Net from client
         25  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
        348  rows processed
给出的执行计划是通过INDEX RANGE SCAN来执行查询

当使用复合索引中所有列时
SQL> select * from mt_biz a where a.hospital_id='4307000009' and a.serial_no='15485197';


执行计划
----------------------------------------------------------
Plan hash value: 2316229530

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

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

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

|   0 | SELECT STATEMENT            |           |     1 |   244 |     1   (0)| 00:00:01 |

|   1 |  TABLE ACCESS BY INDEX ROWID| MT_BIZ    |     1 |   244 |     1   (0)| 00:00:01 |

|*  2 |   INDEX UNIQUE SCAN         | PK_MT_BIZ |     1 |       |     1   (0)| 00:00:01 |

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


Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("A"."HOSPITAL_ID"='4307000009' AND "A"."SERIAL_NO"='15485197')


统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          3  consistent gets
          0  physical reads
          0  redo size
       2818  bytes sent via SQL*Net to client
        232  bytes received via SQL*Net from client
          1  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
给出的执行计划是使用INDEX UNIQUE SCAN索引扫描来查询
所以当创建复合索引后如果查询要想使用这个复合索引就必须在查询条件中
使用复合索引的前导列才会让优化器使用这个复合索引

目录
相关文章
|
8月前
|
SQL 关系型数据库 分布式数据库
数据库内核那些事|细说PolarDB优化器查询变换:IN-List变换
本篇文章将对PolarDB的IN-List变换进行深入阐述,从而让我们对PolarDB的查询改写能力有更感性的认知。
|
6月前
|
SQL 关系型数据库 分布式数据库
数据库内核那些事|细说PolarDB优化器查询变换:IN-List变换
数据库内核那些事|细说PolarDB优化器查询变换:IN-List变换
106 0
|
7月前
|
存储 自然语言处理 关系型数据库
MySQL学习笔记-优化器选索引的因素
MySQL学习笔记-优化器选索引的因素
133 0
|
11月前
|
SQL 算法 Cloud Native
数据库内核那些事|细说PolarDB优化器查询变换 - join消除篇
数据库的查询优化器是整个系统的"大脑",一条SQL语句执行是否高效在不同的优化决策下可能会产生几个数量级的性能差异,因此优化器也是数据库系统中最为核心的组件和竞争力之一。阿里云瑶池旗下的云原生数据库PolarDB MySQL版作为领先的云原生数据库,希望能够应对广泛用户场景、承接各类用户负载,助力企业数据业务持续在线、数据价值不断放大,因此对优化器能力的打磨是必须要做的工作之一。 本系列将从PolarDB for MySQL的查询变换能力开始,介绍我们在这个优化器方向上逐步积累的一些工作。
11357 0
|
SQL Oracle 架构师
PolarDB for MySQL优化器查询变换系列 - join条件下推
本篇是PolarDB 优化器查询变换系列的第四篇,之前的文章请见:窗口函数解相关:https://ata.alibaba-inc.com/articles/194578IN-list变换:https://ata.alibaba-inc.com/articles/254779Join消除:https://ata.alibaba-inc.com/articles/252403引言在数据库的查询优化特性
189 0
PolarDB for MySQL优化器查询变换系列 - join条件下推
|
SQL Cloud Native 算法
PolarDB 优化器查询变换系列 - join消除
背景众所周知,数据库的查询优化器可以说是整个系统的"大脑",一条查询语句执行的是否高效,在不同的优化器决策下,可能会产生几个数量级的性能差异,因此优化器也是数据库系统中最为核心的组件和核心竞争力之一。对于各个商业数据库,其优化器通过常年积累下来的能力,是其最为核心的商业机密,而另一方面从现有的开源数据库来看,很可惜大多数产品的优化器还都十分初级,也包括老牌的MySQL/Post
188 0
|
存储 SQL 关系型数据库
如何优雅的给字段加索引,能引导优化器走索引?
大家好前面我们大概了解了MySQL为什么会选错索引。今天介绍一下如何巧妙的给字符串字段加索引提高查询性能。
如何优雅的给字段加索引,能引导优化器走索引?
|
SQL 存储 关系型数据库
优化器选错索引,导致线上瘫痪
大家好前面我们大概了解了索引如何选择以及利弊问题。今天介绍一下强大的MySQL为什么会选错索引!如果索引选对了事半功倍!
优化器选错索引,导致线上瘫痪
|
SQL 关系型数据库 MySQL
庖丁解牛|图解 MySQL 8.0 优化器查询转换篇
本篇介绍子查询、分析表和JOIN的复杂转换过程
492 0
庖丁解牛|图解 MySQL 8.0 优化器查询转换篇