暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

震惊!没想到Oracle 8i ~19c 都还有这个缺陷

344

 

  前天一个用户出现了一个较为奇怪的问题,统计信息也是最新的【客户跨年收集了统计信息】,但是如果不加Index,则不会走索引,主要来看就是评估的rows不准确。

  当然客户也知道强制加index,效率更高,然而其通过工具查看执行计划发现走索引的情况下,Oracle cbo评估出来的cost非常之高,比走全表还要高。我想想这就是为啥默认不走索引的原因。【文章略长,想看解决方案,可以直接跳到文章最后

SELECT c.LOTNAME, c.CARRIERNAME, c.PROCESSOPERATION, c.TIMEKEY
FROM ct_defectflagproduct c, (select *+INDEX(p LOT_IDX04)*/ * from lot p where LASTEVENTTIMEKEY >= to_char(sysdate - interval '2' day, 'yyyymmddhh24miss') || '000000') l,CT_IMRVREFERENCE PP
WHERE c.TIMEKEY >= to_char(sysdate - interval '2' day, 'yyyymmddhh24miss') || '000000'
AND c.TIMEKEY <= to_char(sysdate, 'yyyymmddhh24miss') || '999999'
AND c.CARRIERNAME = L.CARRIERNAME
AND c.LOTNAME = L.LOTNAME
AND PP.PREPROCESSOPERATIONNAME = c.PROCESSOPERATION
AND PP.PRODUCTSPECNAME = L.PRODUCTSPECNAME
AND L.PROCESSOPERATIONNAME = PP.PROCESSOPERATIONNAME
GROUP BY c.LOTNAME, c.CARRIERNAME, c.PROCESSOPERATION, c.TIMEKEY

上述是原始SQL语句,接下来我们看看执行计划【来自sqlhc报告】。

---------------------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                                | Name                       | E-Rows |E-Bytes| Cost (%CPU)| E-Time   |  OMem |  1Mem | Used-Mem |

---------------------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                         |                            |        |       |  4042K(100)|          |       |       |          |
|   1 |  HASH GROUP BY                           |                            |    121 | 15609 |  4042K  (1)| 00:02:38 |   998K|   998K|  770K (0)|
|*  2 |   FILTER                                 |                            |        |       |            |          |       |       |          |
|   3 |    NESTED LOOPS                          |                            |    121 | 15609 |  4042K  (1)| 00:02:38 |       |       |          |
|   4 |     NESTED LOOPS                         |                            |        |       |            |          |       |       |          |
|*  5 |      HASH JOIN                           |                            |  10636 |   851K|  4041K  (1)| 00:02:38 |  1236K|  1236K| 2422K (0)|
|   6 |       TABLE ACCESS FULL                  | CT_IMRVREFERENCE           |   2720 | 68000 |    11   (0)| 00:00:01 |       |       |          |
|*  7 |       TABLE ACCESS BY INDEX ROWID BATCHED| LOT                        |    382K|    20M|  4041K  (1)| 00:02:38 |       |       |          |
|*  8 |        INDEX RANGE SCAN                  | LOT_IDX04                  |   3925K|       |   161K  (1)| 00:00:07 |       |       |          |
|*  9 |      INDEX RANGE SCAN                    | CT_DEFECTFLAGPRODUCT_INDEX |        |       |            |          |       |       |          |
|* 10 |     TABLE ACCESS BY INDEX ROWID          | CT_DEFECTFLAGPRODUCT       |      1 |    47 |  1622   (2)| 00:00:01 |       |       |          |
---------------------------------------------------------------------------------------------------------------------------------------------------

Query Block Name Object Alias (identified by operation id):

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

   1 - SEL$F5BB74E1
   6 - SEL$F5BB74E1 / PP@SEL$1
   7 - SEL$F5BB74E1 / P@SEL$2
   8 - SEL$F5BB74E1 / P@SEL$2
   9 - SEL$F5BB74E1 / C@SEL$1
  10 - SEL$F5BB74E1 / C@SEL$1

Outline Data
-------------
  *+

      BEGIN_OUTLINE_DATA
      INDEX(@"SEL$F5BB74E1""C"@"SEL$1" ("CT_DEFECTFLAGPRODUCT"."LOTNAME""CT_DEFECTFLAGPRODUCT"."TIMEKEY""CT_DEFECTFLAGPRODUCT"."CARRIERNAME"))
      NLJ_BATCHING(@"SEL$F5BB74E1""C"@"SEL$1")
      USE_NL(@"SEL$F5BB74E1""C"@"SEL$1")
      BATCH_TABLE_ACCESS_BY_ROWID(@"SEL$F5BB74E1""P"@"SEL$2")
      INDEX_RS_ASC(@"SEL$F5BB74E1""P"@"SEL$2" ("LOT"."LASTEVENTTIMEKEY"))
      USE_HASH(@"SEL$F5BB74E1""P"@"SEL$2")
      IGNORE_OPTIM_EMBEDDED_HINTS
      OPTIMIZER_FEATURES_ENABLE('12.2.0.1')
      DB_VERSION('12.2.0.1')
      OPT_PARAM('_optimizer_use_feedback''false')
      ALL_ROWS
      OUTLINE_LEAF(@"SEL$F5BB74E1")
      MERGE(@"SEL$2" >"SEL$1")
      OUTLINE(@"SEL$1")
      OUTLINE(@"SEL$2")
      FULL(@"SEL$F5BB74E1""PP"@"SEL$1")
      LEADING(@"SEL$F5BB74E1""PP"@"SEL$1""P"@"SEL$2""C"@"SEL$1")
      USE_HASH_AGGREGATION(@"SEL$F5BB74E1")
      END_OUTLINE_DATA
  */

Predicate Information (identified by operation id):

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

   2 - filter(TO_CHAR(SYSDATE@!,'yyyymmddhh24miss')||'999999'>=TO_CHAR(SYSDATE@!-INTERVAL'+02 00:00:00' DAY(2) TO
              SECOND(0),'yyyymmddhh24miss')||'000000')
   5 - access("PP"."PRODUCTSPECNAME"="P"."PRODUCTSPECNAME" AND "P"."PROCESSOPERATIONNAME"="PP"."PROCESSOPERATIONNAME")
   7 - filter("P"."CARRIERNAME" IS NOT NULL)
   8 - access("LASTEVENTTIMEKEY">=TO_CHAR(SYSDATE@!-INTERVAL'+02 00:00:00' DAY(2) TO SECOND(0),'yyyymmddhh24miss')||'000000')
   9 - access("C"."LOTNAME"="P"."LOTNAME" AND "C"."TIMEKEY">=TO_CHAR(SYSDATE@!-INTERVAL'+02 00:00:00' DAY(2) TO
              SECOND(0),'yyyymmddhh24miss')||'000000' AND "C"."CARRIERNAME"="P"."CARRIERNAME" AND
              "C"."TIMEKEY"<=TO_CHAR(SYSDATE@!,'yyyymmddhh24miss')||'999999')
       filter("C"."CARRIERNAME"="P"."CARRIERNAME")
  10 - filter("PP"."PREPROCESSOPERATIONNAME"="C"."PROCESSOPERATION")


可以看到LOT这个表走index返回评估了几百万数据,这显示是有问题的,据了解这个表本身也哭1700万条数据而已。

后面检查发现这个表的where条件列实际上并不是date类型,而是varchar2.

对于varchar2用来存时间,这显然是有一些问题的。

SINGLE TABLE ACCESS PATH 
  Single Table Cardinality Estimation for LOT[P] 
  SPD: Directive valid: dirid = 8340008695565278526, state = 1, flags = 1, loc = 1, forDS = NO, forCG = YES {C(116490)[37]}
  SPD: Return code in qosdDSDirSetup: EXISTS, estType = TABLE

 kkecdn: Single Table Predicate:"P"."LASTEVENTTIMEKEY">=TO_CHAR(SYSDATE@!-INTERVAL'+02 00:00:00' DAY(2) TO SECOND(0),'yyyymmddhh24miss')||'000000'
  Column (#37): LASTEVENTTIMEKEY(VARCHAR2)
    AvgLen: 21 NDV: 9138733 Nulls: 0 Density: 0.000000
  Estimated selectivity: 0.222452 , col: #37 

SQL> select to_char(to_number(utl_raw.cast_to_raw('20241231113434000000'))) from dual;

TO_CHAR(TO_NUMBER(UTL_RAW.CAST_TO_RAW('20241231113434000000')))
--------------------------------------------------------------------------------
3230323431323331313133343334303030303030

SQL> select (3230323530313031313932373338313632333534 - 3230323431323331313133343334303030303030)/(3230323530313031313932373338313632333534-3230323130323237323033393333353234363630) from dual;

(3230323530313031313932373338313632333534-32303234313233313131333433343030303030
--------------------------------------------------------------------------------
                                                                      .247480564
                                                                      

SQL> select 17076900*0.247480564 from dual;

17076900*0.247480564
--------------------
          4226200.84

SQL>                                          ``` 


根据cbo评估的选择性计算出来的rows确实是大几百万。

这里我们创建一个测试表在测试环境中验证一下。

SQL> conn roger/roger
Connected.
SQL> drop table test;

Table dropped.

SQL> CREATE TABLE test(
  2      t_date TIMESTAMP,
        v_date varchar2(100)
);  3    4  

Table created.

SQL> 
SQL> BEGIN
  2      FOR i IN 1..1000000 LOOP
        INSERT INTO test (t_date)
        VALUES (
            TO_TIMESTAMP(
                TO_CHAR(
                    TO_DATE('2021-01-01''YYYY-MM-DD') + 
  3    4    5    6    7    8                      DBMS_RANDOM.VALUE(0, (TO_DATE('2025-01-02''YYYY-MM-DD') - TO_DATE('2021-01-01''YYYY-MM-DD'))),
  9                      'YYYY-MM-DD HH24:MI:SS'
                ) || '.' || LPAD(ROUND(DBMS_RANDOM.VALUE(0, 1000000)), 6, '0'), 'YYYY-MM-DD HH24:MI:SS.FF6'
            )
 10   11   12          );
    END LOOP;
    COMMIT;
END;
/ 13   14   15   16  

PL/SQL procedure successfully completed.

SQL>  update testset v_date=to_char(t_date,'yyyymmddhh24missff6');

1000000 rows updated.

SQL> 
SQL> BEGIN
  2      FOR i IN 1..1000000 LOOP
        INSERT INTO test (t_date)
        VALUES (
            TO_TIMESTAMP(
                TO_CHAR(
                    TO_DATE('2021-01-01''YYYY-MM-DD') + 
  3    4    5    6    7    8                      DBMS_RANDOM.VALUE(0, (TO_DATE('2025-01-02''YYYY-MM-DD') - TO_DATE('2021-01-01''YYYY-MM-DD'))),
  9                      'YYYY-MM-DD HH24:MI:SS'
                ) || '.' || LPAD(ROUND(DBMS_RANDOM.VALUE(0, 1000000)), 6, '0'), 'YYYY-MM-DD HH24:MI:SS.FF6'
            )
 10   11   12          );
    END LOOP;
    COMMIT;
END;
/ 13   14   15   16  

PL/SQL procedure successfully completed.

SQL>  update testset v_date=to_char(t_date,'yyyymmddhh24missff6');

1000000 rows updated.

SQL>  EXEC dbms_stats.gather_table_stats(ownname => 'ROGER',tabname =>'TEST', estimate_percent => dbms_stats.auto_sample_size, CASCADE => true, method_opt => 'for all columns size 1', no_invalidate => false);

PL/SQL procedure successfully completed.

SQL> set autot traceonly exp
SQL> select * from testwhere t_date>=to_date('20241231','yyyymmdd');

Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  1366 | 43712 |  2467   (1)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST |  1366 | 43712 |  2467   (1)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - filter("T_DATE">=TIMESTAMP' 2024-12-31 00:00:00')

Note
-----
   - automatic DOP: Computed Degree of Parallelism is 1 because of parallel threshold

SQL> set autot off
SQL> select count(1) from testwhere t_date>=to_date('20241231','yyyymmdd');

  COUNT(1)
----------
      1410


SQL> set autot traceonly exp
SQL> select * from testwhere v_date>='20241231';

Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |   221K|  6929K|  2468   (1)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST |   221K|  6929K|  2468   (1)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - filter("V_DATE">='20241231')

Note
-----
   - automatic DOP: Computed Degree of Parallelism is 1 because of parallel threshold


SQL> set autot off
SQL> select count(1) from testwhere v_date>='20241231';

  COUNT(1)
----------
      1410

SQL> 


大家可以看到,默认没有直方图的情况之下,对于date列的执行计划评估是准确的,test表的rows评估也是准确的。

但是对于v_date这个varchar2的列作为查询条件,我可以发现执行计划rows评估是完全不对的,高达22万【表只有100w条数据】。

实际上我们根据条件count可以发现只有1410条数据

很显然,对于varchar2存存时间列的情况,Oracle CBO的计算评估是有些不妥的。

这里打开10053 event跟踪一下,看下Oracle cbo的成本计算。

***********************
Table Stats::
  Table: TEST  Alias: TEST
#Rows: 1000000  SSZ: 0  LGR: 0  #Blks:  9077  AvgRowLen:  32.00  NEB: 0  ChainCnt:  0.00  ScanRate:  0.00  SPC: 0  RFL: 0  RNF: 0  CBK: 0  CHR: 0  KQDFLG: 1
#IMCUs: 0  IMCRowCnt: 0  IMCJournalRowCnt: 0  #IMCBlocks: 0  IMCQuotient: 0.000000
try to generate single-table filter predicates from ORs for query block SEL$1 (#0)
finally: "TEST"."T_DATE">=TIMESTAMP' 2024-12-31 00:00:00'

=======================================
SPD: BEGIN context at query block level
=======================================
Query Block SEL$1 (#0)
Return code in qosdSetupDirCtx4QB: NOCTX
=====================================
SPD: END context at query block level
=====================================
Access path analysis for TEST
***************************************
SINGLE TABLE ACCESS PATH 
  Single Table Cardinality Estimation for TEST[TEST] 
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = TABLE

 kkecdn: Single Table Predicate:"TEST"."T_DATE">=TIMESTAMP' 2024-12-31 00:00:00'
  Column (#1): T_DATE(TIMESTAMP)
    AvgLen: 11 NDV: 1000000 Nulls: 0 Density: 0.000001 Min: 2459216.000957 Max: 2460677.995189
  Estimated selectivity: 0.001366 , col: #1 
  Table: TEST  Alias: TEST
    Card: Original: 1000000.000000rsel = 0.001366   Rounded: 1366  Computed: 1365.703654  Non Adjusted: 1365.703654
  Scan IO  Cost (Disk) =   2460.000000
  Scan CPU Cost (Disk) =   214668630.880000
  Cost of predicates:
    io = NOCOST, cpu = 50.000000, sel = 0.001366 flag = 2048  ("TEST"."T_DATE">=TIMESTAMP' 2024-12-31 00:00:00')
  Total Scan IO  Cost  =   2460.000000 (scan (Disk))
                         + 0.000000 (io filter eval) (= 0.000000 (per row) * 1000000.000000 (#rows))
                       =   2460.000000
  Total Scan CPU  Cost =   214668630.880000 (scan (Disk))
                         + 50000000.000000 (cpu filter eval) (= 50.000000 (per row) * 1000000.000000 (#rows))
                       =   264668630.880000
  Access Path: TableScan
    Cost:  2467.098829  Resp: 2467.098829  Degree: 0
      Cost_io: 2460.000000  Cost_cpu: 264668631
      Resp_io: 2460.000000  Resp_cpu: 264668631
  Best:: AccessPath: TableScan
         Cost: 2467.098829  Degree: 1  Resp: 2467.098829  Card: 1365.703654  Bytes: 0.000000
         
         

***************************************
SINGLE TABLE ACCESS PATH 
  Single Table Cardinality Estimation for TEST[TEST] 
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = TABLE

 kkecdn: Single Table Predicate:"TEST"."V_DATE">='20241231'
  Column (#2): V_DATE(VARCHAR2)
    AvgLen: 21 NDV: 1000000 Nulls: 0 Density: 0.000001
  Estimated selectivity: 0.221756 , col: #2 
  Table: TEST  Alias: TEST
    Card: Original: 1000000.000000rsel = 0.221756   Rounded: 221756  Computed: 221755.578793  Non Adjusted: 221755.578793
  Scan IO  Cost (Disk) =   2460.000000
  Scan CPU Cost (Disk) =   234641310.880000
  Cost of predicates:
    io = NOCOST, cpu = 50.000000, sel = 0.221756 flag = 2048  ("TEST"."V_DATE">='20241231')
  Total Scan IO  Cost  =   2460.000000 (scan (Disk))
                         + 0.000000 (io filter eval) (= 0.000000 (per row) * 1000000.000000 (#rows))
                       =   2460.000000
  Total Scan CPU  Cost =   234641310.880000 (scan (Disk))
                         + 50000000.000000 (cpu filter eval) (= 50.000000 (per row) * 1000000.000000 (#rows))
                       =   284641310.880000
  Access Path: TableScan
    Cost:  2467.634527  Resp: 2467.634527  Degree: 0
      Cost_io: 2460.000000  Cost_cpu: 284641311
      Resp_io: 2460.000000  Resp_cpu: 284641311
  Best:: AccessPath: TableScan
         Cost: 2467.634527  Degree: 1  Resp: 2467.634527  Card: 221755.578793  Bytes: 0.000000

很明显对于date列的选择性计算【Estimated selectivity: 0.001366 】是相对准确的;而varchar2这个列的评估就比较大了【Estimated selectivity: 0.221756】

参考基于Oracle成本优化一书中可以得知对于无直方图的请下,选择性计算大致是如下这个公式: Selectivity = (high_value – limit) (high_value – low_value) + 1/num_distinct

这里我可以大致计算一下:

SQL> l
  1  select TABLE_NAME,COLUMN_NAME,NUM_DISTINCT,HIGH_VALUE,LOW_VALUE,DENSITY,NUM_NULLS
  2* from dba_tab_col_statistics where table_name='TEST' and owner='ROGER'
SQL>

TABLE_NAME   COLUMN_NAME     NUM_DISTINCT HIGH_VALUE                                  LOW_VALUE                                    DENSITY  NUM_NULLS
------------ --------------- ------------ ------------------------------------------- ----------------------------------------- ---------- ----------
TEST         T_DATE               1000000 787D010118360512F40D00                      7879010101021728400038                       .000001          0
TEST         V_DATE               1000000 3230323530313031323335333034333137393834    3230323130313031303030313232363735323833     .000001          0

SQL>       
SQL>  select to_char(to_number(utl_raw.cast_to_raw('20241231000000000000'))) from dual;

TO_CHAR(TO_NUMBER(UTL_RAW.CAST_TO_RAW('20241231')))
--------------------------------------------------------------------------------
3230323431323331303030303030303030303030

SQL> 
SQL> select (3230323530313031323335333034333137393834 - 3230323431323331303030303030303030303030)/(3230323530313031323335333034333137393834-3230323130313031303030313232363735323833) from dual;

(3230323530313031323335333034333137393834-3230323431323331303030303030303030303030)/(3230323530313031323335333034333137393834-3230323130313031303030313232363735323833)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------
                                                                                                                                                              .24747425

SQL>

可以看到计算出来的值cbo评估的是接近的,总之。都不太对,这个数据太大太大。

如果存在直方图的情况下,这个问题会如何呢?

SQL> EXEC dbms_stats.gather_table_stats(ownname => 'ROGER',tabname =>'TEST', estimate_percent => dbms_stats.auto_sample_size, CASCADE => true, method_opt => 'for all columns size auto', no_invalidate => false);

PL/SQL procedure successfully completed.

SQL> set lines 230
SQL> @tab_stat 

TABLE_NAME COLUMN_NAME   NUM_DISTINCT HIGH_VALUE                                    LOW_VALUE                                        DENSITY  NUM_NULLS NUM_BUCKETS HISTOGRAM
---------- ------------- ------------ --------------------------------------------- --------------------------------------------- ---------- ---------- ----------- -----------
TEST       T_DATE             1000000 787D010118360512F40D00                        7879010101021728400038                           .000001          0           1 NONE
TEST       V_DATE             1000000 3230323530313031323335333034333137393834      3230323130313031303030313232363735323833         .000001          0         254 HYBRID

SQL>   

SQL> set autot traceonly exp
SQL> select * from testwhere v_date>='20241231';

Execution Plan
----------------------------------------------------------
Plan hash value: 1357081020

--------------------------------------------------------------------------
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |  4064 |   127K|  2468   (1)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST |  4064 |   127K|  2468   (1)| 00:00:01 |
--------------------------------------------------------------------------

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

   1 - filter("V_DATE">='20241231')

Note
-----
   - automatic DOP: Computed Degree of Parallelism is 1 because of parallel threshold

SQL> 

可以看到有直方图的情况下,评估的信息是相对准确的【4064和实际的rows 1410 差距不大】。

同样此时的10053 event跟踪所看到的信息如下:

SINGLE TABLE ACCESS PATH 
  Single Table Cardinality Estimation for TEST[TEST] 
  SPD: Return code in qosdDSDirSetup: NOCTX, estType = TABLE

 kkecdn: Single Table Predicate:"TEST"."V_DATE">='20241231'
  Column (#2): 
    NewDensity:0.000001, OldDensity:0.000001 BktCnt:5411.000000, PopBktCnt:0.000000, PopValCnt:0, NDV:1000000
  Column (#2): V_DATE(VARCHAR2)
    AvgLen: 21 NDV: 1000000 Nulls: 0 Density: 0.000001
    Histogram: Hybrid  #Bkts: 254  UncompBkts: 5411  EndPtVals: 254  ActualVal: yes
  Estimated selectivity: 0.004064 , col: #2 
  Table: TEST  Alias: TEST
    Card: Original: 1000000.000000rsel = 0.004064   Rounded: 4064  Computed: 4064.066982  Non Adjusted: 4064.066982
  Scan IO  Cost (Disk) =   2460.000000
  Scan CPU Cost (Disk) =   234641310.880000
  Cost of predicates:
    io = NOCOST, cpu = 50.000000, sel = 0.004064 flag = 2048  ("TEST"."V_DATE">='20241231')
  Total Scan IO  Cost  =   2460.000000 (scan (Disk))
                         + 0.000000 (io filter eval) (= 0.000000 (per row) * 1000000.000000 (#rows))
                       =   2460.000000
  Total Scan CPU  Cost =   234641310.880000 (scan (Disk))
                         + 50000000.000000 (cpu filter eval) (= 50.000000 (per row) * 1000000.000000 (#rows))
                       =   284641310.880000
  Access Path: TableScan
    Cost:  2467.634527  Resp: 2467.634527  Degree: 0
      Cost_io: 2460.000000  Cost_cpu: 284641311
      Resp_io: 2460.000000  Resp_cpu: 284641311
  Best:: AccessPath: TableScan
         Cost: 2467.634527  Degree: 1  Resp: 2467.634527  Card: 4064.066982  Bytes: 0.000000

根据cbo评估的选择性可以计算得到和执行计划一样的rows评估。

SQL> select 1000000*0.004064 from dual;

1000000*0.004064
----------------
            4064

SQL>

当然对于这个,解决方案主要有2个:

1、固定执行计划,比如sql profile固定即可,强制走index。 

2、针对该表的统计信息收集需要单独收集直方图。 

3、where 条件列再套一层to_date函数,这样cbo是可以识别的,cbo评估相对准确。至少差异不会那么大。

不过从根因上来讲,这属于开发不规范,使用varchar2类存时间,而Oracle并不知道所存的是时间,那么评估则会存在异常。

~~~~~~~~~~~~~~~~~~~~~~~~~~~

最近和一部分行业数据库专家成了一个数据库交流付费群。

加入DataBase Fans付费群,您能有哪些收获?

1、大家可与顶级数据库专家互动,问题范围不限于Oracle,MySQL,PostgreSQL,openGauss等。

2、群里有哪些数据库专家?

     - 某MySQL 源码专家xx{打个码}

    -  PostgreSQL实战专家灿灿

    -  Oracle专家 Roger以及另外2位Oracle 实战派ACE专家【匿名一下:擅长SQL优化,优化器】

     - 是的,大家没有看错,全都是实战派高手!
    
     -  最近付费群又加入了一个顶级SQL高手,传闻itpub论坛top 级别的存在

2、 入群可以获得群里专家们的收藏脚本。

3、 可提供数据库相关资料共享【包括xxxx账号,你们懂的】

4、 不定期组织直播案例分析【包括但不限于Oracle、MySQL、国产xxx数据库】

5、 付费群:365人/年 【2025/1/1 - 2025/12/31】

想加入的朋友,速进!前100名299,满100名后恢复原价! 

扫码加管理员微信咨询 Roger_database



文章转载自Roger的数据库专栏,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论