One of the most important considerations when writing a select statement against a large table is the effective use of an index. However this is sometimes more easily said than done. Have you ever found that your WHERE clause is missing just one field of an index and that field is not at the end of the index?

There are some situations where you can make more effective use of the entire index even if you are missing a field. Here is a simple trick to help you do just that. If the field you are missing cannot contain too many entries, then if you create a range table with all possible entries and add that range table to your WHERE clause, you can dramatically speed up a SELECT statement. Even when you take into account the extra time needed to retrieve the key fields, the results are worth it. This may seem a bit counter-intuitive, but the example code shows what I'm doing (but be careful – if you run this code in a QA environment, it may take a while):

代码如下:

REPORT ztest_indexed_selects.

PARAMETERS: p_bukrs   LIKE bkpf-bukrs MEMORY ID buk      OBLIGATORY,
            p_belnr   LIKE bkpf-belnr MEMORY ID bln      OBLIGATORY,
            p_gjahr   LIKE bkpf-gjahr MEMORY ID gjr      OBLIGATORY.

TYPES: BEGIN OF bkpf_fields,
         bukrs    LIKE bkpf-bukrs,
         belnr    LIKE bkpf-belnr,
         gjahr    LIKE bkpf-gjahr,
         blart    LIKE bkpf-blart,
         budat    LIKE bkpf-budat,
       END   OF bkpf_fields.

DATA: bkpf  TYPE bkpf,
      dd07l TYPE dd07l.

DATA: bkpf_int TYPE TABLE OF bkpf_fields,
      bkpf_wa  TYPE          bkpf_fields.

DATA: start   TYPE i,
      end     TYPE i,
      dif     TYPE i.

START-OF-SELECTION.
  PERFORM get_one_document.
  PERFORM unindexed_select_bkpf.
  PERFORM indexed_select_bkpf.
  PERFORM unindexed_select_bkpf_2.
  PERFORM indexed_select_bkpf_2.

*&---------------------------------------------------------------------*
*&      Form  get_one_document
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM get_one_document.

* First we get a single document using a select statement that is
* fully qualified on the primary key. Because buffering may be an issue,
* the first select will be disregarded in this test. However, in real
* life, this would be the important time.

* Initial select
  SELECT  bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE bukrs = p_bukrs
    AND   belnr = p_belnr
    AND   gjahr = p_gjahr.

IF sy-subrc <> 0.
    MESSAGE ID '00' TYPE 'E' NUMBER '001' WITH
               'Document does not exist'.
  ENDIF.

* Next we get the same document using the same fully qualified select
* statement. We will use the time for this in comparisons.

REFRESH bkpf_int.
  GET RUN TIME FIELD start.

SELECT  bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE bukrs = p_bukrs
    AND   belnr = p_belnr
    AND   gjahr = p_gjahr.

GET RUN TIME FIELD end.
  dif = end - start.
  WRITE: /001 'Time for first (fully qualified) select',
          067  ':', dif, 'microseconds'.
  SKIP 1.

* So we can use these fields later on
  READ TABLE bkpf_int INTO bkpf_wa INDEX 1.

ENDFORM.                    " get_one_document

*&---------------------------------------------------------------------*
*&      Form  unindexed_select_bkpf
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM unindexed_select_bkpf.

* Now we select a group of documents using a select statement that is
* missing the company code from the primary key. This may return a
* different set of documents from the first select, but we are just
* interested in how long it takes.

* Initial select

REFRESH bkpf_int.
  SELECT  bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE belnr = p_belnr
    AND   gjahr = p_gjahr.

REFRESH bkpf_int.
  GET RUN TIME FIELD start.

* Use this select in comparisons
  SELECT  bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE belnr = p_belnr
    AND   gjahr = p_gjahr.

GET RUN TIME FIELD end.
  dif = end - start.
  WRITE: /001 'Time for second (unindexed) select',
          067  ':', dif, 'microseconds'.

ENDFORM.                    " unindexed_select_bkpf

*&---------------------------------------------------------------------*
*&      Form  indexed_select_bkpf
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM indexed_select_bkpf.

* Now we're going to use the first trick. Go to table T001 (company
* codes) and retrieve all the company codes and put them into a range
* table. We'll put the range table into the select. So long as the
* number of company codes is not too great, this will speed up the
* select on BKPF.

RANGES: r_bukrs FOR bkpf-bukrs.

* Preliminary selects
  r_bukrs-option = 'EQ'.
  r_bukrs-sign   = 'I'.
  SELECT bukrs
    FROM t001
    INTO r_bukrs-low.
    APPEND r_bukrs.
  ENDSELECT.

REFRESH bkpf_int.
  SELECT  bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE bukrs IN r_bukrs
    AND   belnr = p_belnr
    AND   gjahr = p_gjahr.

REFRESH: bkpf_int,
           r_bukrs.
  GET RUN TIME FIELD start.

* Use these selects in comparison
  r_bukrs-option = 'EQ'.
  r_bukrs-sign   = 'I'.
  SELECT bukrs
    FROM t001
    INTO r_bukrs-low.
    APPEND r_bukrs.
  ENDSELECT.

SELECT bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE bukrs IN r_bukrs
    AND   belnr = p_belnr
    AND   gjahr = p_gjahr.

GET RUN TIME FIELD end.
  dif = end - start.
  WRITE: /001 'Time for third select',
              '(indexed by selecting from the check table)',
          067  ':', dif, 'microseconds'.
  SKIP 1.

ENDFORM.                    " indexed_select_bkpf

*&---------------------------------------------------------------------*
*&      Form  unindexed_select_bkpf_2
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM unindexed_select_bkpf_2.

* Now we'll get another group of records from BKPF. There is a
* secondary index on BKPF with fields BUKRS, BSTAT and BUDAT.
* We're going to leave BSTAT out of the select and use
* BUKRS and BUDAT from the first document we selected.

* Preliminary select - to be ignored.
  REFRESH bkpf_int.
  SELECT  bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE bukrs = p_bukrs
    AND   budat = bkpf_wa-budat.

REFRESH bkpf_int.
  GET RUN TIME FIELD start.

SELECT bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE bukrs = p_bukrs
    AND   budat = bkpf_wa-budat.

GET RUN TIME FIELD end.
  dif = end - start.
  WRITE: /001 'Time for fourth (partially indexed) select',
          067  ':', dif, 'microseconds'.

ENDFORM.                    " unindexed_select_bkpf_2

*&---------------------------------------------------------------------*
*&      Form  indexed_select_bkpf_2
*&---------------------------------------------------------------------*
*       text
*----------------------------------------------------------------------*
FORM indexed_select_bkpf_2.

* Finally, we will use the domain values of BSTAT in the select. If you
* are sure that you know all of the values, you can hardcode them. I am
* using all of the possible values of BSTAT so that all three selects
* return the same data. In practice, we would probably narrow it down.
* But since normal FI postings have BSTAT = SPACE, this won't help
* unless we are looking for 'not' normal documents.

RANGES: r_bstat FOR bkpf-bstat.
  DATA  : d1 LIKE dd07l-domvalue_l,
          d2 LIKE dd07l-domvalue_h.

* Hardcoded values
* Preliminary select.
  REFRESH bkpf_int.
  SELECT  bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE bukrs EQ p_bukrs
    AND   bstat IN (' ', 'A', 'B', 'D', 'M', 'S', 'V', 'W', 'Z')
    AND   budat = bkpf_wa-budat.

REFRESH bkpf_int.
  GET RUN TIME FIELD start.
* Use this select in comparisons
  SELECT  bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE bukrs EQ p_bukrs
    AND   bstat IN (' ', 'A', 'B', 'D', 'M', 'S', 'V', 'W', 'Z')
    AND   budat = bkpf_wa-budat.

GET RUN TIME FIELD end.
  dif = end - start.
  WRITE: /001 'Time for fifth select',
              '(indexed by hardcoding the domain values)',
          067  ':', dif, 'microseconds'.

* After an upgrade, the values in a domain may change. It's safer to
* retrieve all of the values from the data dictionary. There is a very
* slight increase in the time.

r_bstat-sign   = 'I'.
  SELECT  domvalue_l domvalue_h
    FROM  dd07l
    INTO  (d1, d2)
    WHERE domname  = 'BSTAT'
    AND   as4local = 'A'.
    IF d2 IS INITIAL.
      r_bstat-option = 'EQ'.
      r_bstat-low    = d1.
      CLEAR r_bstat-high.
    ELSE.
      r_bstat-option = 'BT'.
      r_bstat-low    = d1.
      r_bstat-high   = d2.
    ENDIF.
    APPEND r_bstat.
  ENDSELECT.

REFRESH bkpf_int.
  SELECT  bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE bukrs EQ p_bukrs
    AND   bstat IN r_bstat
    AND   budat = bkpf_wa-budat.

REFRESH: bkpf_int,
           r_bstat.

* Use this select in comparisons.
  GET RUN TIME FIELD start.

r_bstat-sign   = 'I'.
  SELECT  domvalue_l domvalue_h
    FROM  dd07l
    INTO  (d1, d2)
    WHERE domname  = 'BSTAT'
    AND   as4local = 'A'.
    IF d2 IS INITIAL.
      r_bstat-option = 'EQ'.
      r_bstat-low    = d1.
      CLEAR r_bstat-high.
    ELSE.
      r_bstat-option = 'BT'.
      r_bstat-low    = d1.
      r_bstat-high   = d2.
    ENDIF.
    APPEND r_bstat.
  ENDSELECT.

REFRESH bkpf_int.
  SELECT  bukrs belnr gjahr blart budat
    FROM  bkpf
    INTO  TABLE bkpf_int
    WHERE bukrs EQ p_bukrs
    AND   bstat IN r_bstat
    AND   budat = bkpf_wa-budat.

GET RUN TIME FIELD end.
  dif = end - start.
  WRITE: /001 'Time for sixth select',
              '(indexed by selecting the domain values)',
          067  ':', dif, 'microseconds'.

ENDFORM.                    " indexed_select_bkpf_2

I ran the above code in QA instances with a DB2 environment in both 4.6C and 4.7. There are more indexes on BKPF in 4.7, but I tried to use one that is in both versions. I also ran a similar program in Oracle with comparable results. But I really don’t know if it will work with other databases – please let me know!

I ran this many times in both active and quiet systems. Here are some typical results:


Time for first (fully qualified) select : 148 microseconds

Time for second (unindexed) select : 1,873,906 microseconds
Time for third select (indexed by selecting from the check table) : 455 microseconds

Time for fourth (partially indexed) select : 816,253 microseconds
Time for fifth select (indexed by hardcoding the domain values) : 43,259 microseconds
Time for sixth select (indexed by selecting the domain values) : 43,332 microseconds

Some things to note:

In the above times, the first select shows what happens in the ideal world. We are comparing select 2 against select 3 and select 4 against selects 5 and 6. But selects 2 and 3 should return the same results as should selects 4, 5 and 6.

But the point is that even though start out knowing nothing about (and presumably not caring about) the company code in selects 2 and 3 and the document status in selects 4, 5 and 6, if you put all possible values of these fields into the select statement, the results are dramatic.

If you try to combine both tricks, you will probably find that they don’t work very well together. Once seems to be enough.

ABAP--在查询条件只包含部分索引字段时,如何使用索引的更多相关文章

  1. IE浏览器URL中的查询条件中包含中文时报404的解决办法

    情况是比如我输入如下URL到IE浏览器: http://localhost:8090/RPT_TYSH_JL_ZD_DETAIL.html?pageIndex=1&year=2018& ...

  2. Linq查询条件里有可空字段比较时报错variable '<>h__TransparentIdentifier2' of type referenced from scope '', but it is not defined

    当我运行下面的linq查询时报了这个错,   1: var result = (from so in svcContext.new_sales_orderSet 2: join soitem in s ...

  3. MongoDB中关于查询条件中包括集合中字段的查询

    要查询的数据结构例如以下: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvZ2FvMzY5NTE=/font/5a6L5L2T/fontsize/400/f ...

  4. sql通配符+sql中查询条件包含下划线等通配符的写法

    一.SQL 通配符 在搜索数据库中的数据时,SQL 通配符可以替代一个或多个字符. SQL 通配符必须与 LIKE 运算符一起使用. 在 SQL 中,可使用以下通配符: 通配符 描述 % 替代一个或多 ...

  5. 使用SQL语句查询某表中所有的主键、唯一索引以及这些主键、索引所包含的字段(转)

    SELECT 索引名称 = a.name , 表名 = c.name , 索引字段名 = d.name , 索引字段位置 = d.colid FROM sysindexes a JOIN sysind ...

  6. SQL Server 存储过程中处理多个查询条件的几种常见写法分析,我们该用那种写法

    本文出处: http://www.cnblogs.com/wy123/p/5958047.html 最近发现还有不少做开发的小伙伴,在写存储过程的时候,在参考已有的不同的写法时,往往很迷茫,不知道各种 ...

  7. 利用查询条件对象,在Asp.net Web API中实现对业务数据的分页查询处理

    在Asp.net Web API中,对业务数据的分页查询处理是一个非常常见的接口,我们需要在查询条件对象中,定义好相应业务的查询参数,排序信息,请求记录数和每页大小信息等内容,根据这些查询信息,我们在 ...

  8. MySQL索引的缺点以及MySQL索引在实际操作中有哪些事项

    以下的文章主要介绍的是MySQL索引的缺点以及MySQL索引在实际操作中有哪些事项是值得我们大家注意的,我们大家可能不知道过多的对索引进行使用将会造成滥用.因此MySQL索引也会有它的缺点: 虽然索引 ...

  9. SQL查询优化联合索引 与 单一列的索引

    目前WEB的普及太快,在实际的开发中,一旦遇到大数据量的时候就需要做到优化,让查询的更快,才能给客户更好的体验,也能够在程序上避免timeout. 部分转载自:https://www.cnblogs. ...

随机推荐

  1. web接口测试之GET与POST请求

    关于HTTP协议,我考虑了一下觉得没必要再花一节内容来介绍,因为网上关于HTTP协议的介绍非常详细.本着以尽量避免介绍一空洞了概念与理论来介绍接口测试,我这里仍然会给出具体实例. 在此之前先简单的介绍 ...

  2. Spring Setter Injection and Constructor Injection

    Setter Injection AppContext.xml <?xml version="1.0" encoding="UTF-8"?> < ...

  3. Android安装BusyBox(三星N7108)

    近期公司安卓app测试,分配任务为监控APP内存.CPU占用率.因安卓是基于linux开发,故很容易就联想使用Linux监控相关的命令.想法总是美好的,现实总是残酷的,使用三星 Galaxy Note ...

  4. 大M法(Big M Method)

    前面一篇讲的单纯形方法的实现,但程序输入的必须是已经有初始基本可行解的单纯形表. 但实际问题中很少有现成的基本可行解,比如以下这个问题: min f(x) = –3x1 +x2 + x3 s.t. x ...

  5. Struts2 源码分析——过滤器(Filter)

    章节简言 上一章笔者试着建一个Hello world的例子.是一个空白的struts2例子.明白了运行struts2至少需要用到哪一些Jar包.而这一章笔者将根据前面章节(Struts2 源码分析—— ...

  6. MySQL5.7(5.6)GTID环境下恢复从库思(qi)路(yin)方(ji)法(qiao)

      要讨论如何恢复从库,我们得先来了解如下一些概念: GTID_EXECUTED:它是一组包含已经记录在二进制日志文件中的事务集合 GTID_PURGED:它是一组包含已经从二进制日志删除掉的事务集合 ...

  7. Auto Mapper03

      经过上一篇博客的学习,大体了解了Auto Mapper的运行机制和操作流程.我们下来学习下,AutoMapper里面具体的一些东西. 一:规则       当我们使用AutoMapper创建实体和 ...

  8. C#开源

    商业协作和项目管理平台-TeamLab 网络视频会议软件-VMukti 驰骋工作流程引擎-ccflow [免费]正则表达式测试工具-Regex-Tester Windows-Phone-7-SDK E ...

  9. JS框架avalon简单例子 行编辑 添加 修改 删除 验证

    为什么要写这个例子:做表单的时候,表单包含主子表,对于子表的编辑,使用的是easyui datagrid的行编辑功能,由于业务比较复杂,实现起来比较麻烦,代码写的也很多,因为插件的封装,无法操作原始的 ...

  10. 基于C#的MongoDB数据库开发应用(3)--MongoDB数据库的C#开发之异步接口

    在前面的系列博客中,我曾经介绍过,MongoDB数据库的C#驱动已经全面支持异步的处理接口,并且接口的定义几乎是重写了.本篇主要介绍MongoDB数据库的C#驱动的最新接口使用,介绍基于新接口如何实现 ...