Application Development and Automation Discussions
Join the discussions or start your own on all things application development, including tools and APIs, programming models, and keeping your skills sharp.
cancel
Showing results for 
Search instead for 
Did you mean: 
Read only

Select performance issue

Former Member
0 Likes
1,769

SELECT vbap~matnr

vbak~vbeln

vbak~vdatu

vbap~kwmeng

vbap~pstyv

INTO CORRESPONDING FIELDS OF TABLE lt_so_required

FROM vbak JOIN vbap

ON vbakvbeln = vbapvbeln

FOR ALL entries IN it_matnr

WHERE vbap~matnr = it_matnr-matnr

AND vbap~werks IN is_sel_scr-werks

AND vbak~vdatu BETWEEN is_sel_scr-d_start

AND is_sel_scr-d_end

AND vbak~auart IN is_sel_scr-auart

AND vbak~vkorg = is_sel_scr-vkorg

AND vbak~vtweg IN is_sel_scr-vtweg

AND vbak~spart IN is_sel_scr-spart

AND ( vbap~pstyv IN is_sel_scr-pstyvs OR

vbap~pstyv IN is_sel_scr-pstyvo ).

Could you please point out the way of improving this select?

16 REPLIES 16
Read only

yuri_ziryukin
Product and Topic Expert
Product and Topic Expert
0 Likes
1,598

SELECT vbap~matnr

> vbak~vbeln

> vbak~vdatu

> vbap~kwmeng

> vbap~pstyv

> INTO CORRESPONDING FIELDS OF TABLE lt_so_required

> FROM vbak JOIN vbap

> ON vbakvbeln = vbapvbeln

> FOR ALL entries IN it_matnr

> WHERE vbap~matnr = it_matnr-matnr

> AND vbap~werks IN is_sel_scr-werks

> AND vbak~vdatu BETWEEN is_sel_scr-d_start

> AND is_sel_scr-d_end

> AND vbak~auart IN is_sel_scr-auart

> AND vbak~vkorg = is_sel_scr-vkorg

> AND vbak~vtweg IN is_sel_scr-vtweg

> AND vbak~spart IN is_sel_scr-spart

> AND ( vbap~pstyv IN is_sel_scr-pstyvs OR

> vbap~pstyv IN is_sel_scr-pstyvo ).

>

> Could you please point out the way of improving this select?

Hello Wojciech,

please use the "index" table VAPMA for your selection and join it with VBAP.

The only field from VBAK I could not find in VAPMA is the VDATU. Please check if you can replace it with another field like AUDAT or some date field from VBAP.

Then your select would look like:

>SELECT vapma~matnr

> vapma~vbeln

> vapma~audat <---- see my comment above about the date

> vbap~kwmeng

> vbap~pstyv

> INTO CORRESPONDING FIELDS OF TABLE lt_so_required

> FROM vapma INNER JOIN vbap

> ON vapmavbeln = vbapvbeln AND vapmaposnr = vbapposnr

> FOR ALL entries IN it_matnr

> WHERE vapma~matnr = it_matnr-matnr

> AND vapma~werks IN is_sel_scr-werks

> AND vapma~audat BETWEEN is_sel_scr-d_start <---- see my comment about the date

> AND is_sel_scr-d_end

> AND vapma~auart IN is_sel_scr-auart

> AND vapma~vkorg = is_sel_scr-vkorg

> AND vapma~vtweg IN is_sel_scr-vtweg

> AND vapma~spart IN is_sel_scr-spart

> AND ( vbap~pstyv IN is_sel_scr-pstyvs OR

> vbap~pstyv IN is_sel_scr-pstyvo ).

Better results will be achieved if you also pass the value of VAPMA~TRVOG (Transaction Group) in the select.

Regards,

Yuri

Read only

0 Likes
1,598

unfortunately the date field is needed 😕

is there any sense making the index on the tables?

Read only

yuri_ziryukin
Product and Topic Expert
Product and Topic Expert
0 Likes
1,598

unfortunately the date field is needed :/

>

> is there any sense making the index on the tables?

Hello Wojciech,

if this field is needed, then include VBAK as the third table in the join.

It might be beneficial to create a secondary index for VAPMA with the fields that are always specified in your selection. Due to the usage of select options I cannot see what else except material number is always (or very often) passed to the SELECT.

Regards,

Yuri

Read only

mayankmrai
Explorer
0 Likes
1,598

Hi,

Better use for all entries in select query instead of inner join..

Read only

yuri_ziryukin
Product and Topic Expert
Product and Topic Expert
0 Likes
1,598

Hi,

>

> Better use for all entries in select query instead of inner join..

Better read corresponding threads with the discussion FAE vs JOIN and do not give useless and wrong advices.

Read only

naveen_inuganti2
Active Contributor
0 Likes
1,598

Hi,

Don't use 'Into Corresponding Fields Of' addition. Instead of that, you can declare structure(ref. internal table) with fields in same order they appear in SELECT query.

Don't use BETWEEN statement, instead of that you might want to look at other options like ranges table etc.,

Never go for OR statement because this causes double search on database. it's better to get all records instead and process what ever are required.

Index Utility:

Ex: F1, F2, F3, F4 are fields and followed same order in index creation -->

F1, F2, F3 = using this in SELECT query triggers index

F2, F3, F4 = Using this in SELECT triggers index

F1, F2, F3, F4 = Also triggers Index

F1, F3, F4 = Never triggers index as was broken at F2

Try to add following oracle hint at the end of the SELECT query - This speeds up FOR ALL ENTRIES query as we are passing blocking factor as 10 and 100. NOTE: This does not apply if amount of data is less.

%_hints oracle '&min_in_blocking_factor 10&&max_in_blocking_factor 100&&min_blocking_factor 10&&max_blocking_factor 100&'.

Thanks,

Naveen Inuganti

Read only

0 Likes
1,598

Hi,

>

> Don't use 'Into Corresponding Fields Of' addition. Instead of that, you can declare structure(ref. internal table) with fields in same order they appear in SELECT query.

>

> Don't use BETWEEN statement, instead of that you might want to look at other options like ranges table etc.,

>

> Never go for OR statement because this causes double search on database. it's better to get all records instead and process what ever are required.

>

> Index Utility:

> Ex: F1, F2, F3, F4 are fields and followed same order in index creation -->

> F1, F2, F3 = using this in SELECT query triggers index

> F2, F3, F4 = Using this in SELECT triggers index

> F1, F2, F3, F4 = Also triggers Index

> F1, F3, F4 = Never triggers index as was broken at F2

>

>

> Try to add following oracle hint at the end of the SELECT query - This speeds up FOR ALL ENTRIES query as we are passing blocking factor as 10 and 100. NOTE: This does not apply if amount of data is less.

> %_hints oracle '&min_in_blocking_factor 10&&max_in_blocking_factor 100&&min_blocking_factor 10&&max_blocking_factor 100&'.

>

> Thanks,

> Naveen Inuganti

1. "into corresponding fields" overhead is so little, that it should not be considered. So your advice number 1 is useless.

2. What is a difference between "BETWEEN" statement and a range like "I BT XXX YYY"? Please support your statement with a link to an explanation.

3. Second advice of not using OR statement is again wrong. It is not better to get all data from the DB and filter in ABAP. This has been discussed in many threads already.

4. I have no idea what "index utility" is mentioned, but the text is simply wrong and confusing.

Four useless/wrong advices in one post is too much for me...

Read only

0 Likes
1,598

Yuri,

Thanks for going through all my options. Also please try it in editor once and come back here.

I have tried all of them, not my assumptions.

Thanks,

Naveen Inuganti

Read only

0 Likes
1,598

Naveen - if you go through old forum posts, you'll find that Yuri is correct.

And I have tried all of your options

Rob

Read only

0 Likes
1,598

Rob,

As Yuri said, every thing is incorrect... let me take few cases:

On OR Statement

In some cases, it can be beneficial to simplify the WHERE conditions used on a LOOP iterator. For example, if you have several conditions that check the same field against a set of values using OR operators, it can be beneficial to place the conditions in a RANGE or SELECT-OPTION object and change the WHERE clause to: WHERE field IN [range] | [select-option]. The IN can be processed faster than several conditional statements joined by an OR (assuming you are using the same field as an operator). Example:

GOOD: u2026 WHERE field1 IN range1.

NOT AS GOOD: u2026 WHERE field1 = v1 OR field1 = v2 OR field1 = v3 OR field1 = v4.

On For All Entries

When using the FOR ALL ENTRIES clause, performance can be improved by increasing the blocking factor. Since the FOR ALL ENTRIES clause essentially breaks down a table of records to be read into individual requests, the blocking factor controls how many of those records are grouped into a single request to the database. The default blocking factor is 5. For example, if the FOR ALL ENTRIES table contains 100 entries and the default blocking factor is used, then 20 separate requests for 5 records each will be sent to the database. If the blocking factor is increased to 100, then only 1 request would be sent to the database to retrieve all 100 records. This reduces the overhead needed to retrieve the data. Be careful not to increase the blocking factor too high as it increases the length of the query and there are maximum limitations in the database that will generate a short-dump if exceeded. The following Oracle u201Chintu201D can be added to queries to increase the blocking factor to 100 for that specific query only: %_HINTS ORACLE '&min_in_blocking_factor 10&&max_in_blocking_factor 100&&min_blocking_factor 10&&max_blocking_factor 100&'. Note that this hint will only optimize database queries when the FOR ALL ENTRIES clause is used and there are at least 100 entries expected in the result set

On Index

Whenever possible, provide all fields in the primary key or index in the WHERE clause without gaps. Itu2019s OK to leave a field off at the end of the primary key or index, but gaps within the primary key or index should be avoided. For example, if an index is comprised of f1, f2, f3 and f4, then the following applies:

u2022 WHERE f1= v1 AND f2 = v2 AND f3 = v3 AND f4 = v4 OK

u2022 WHERE f1=v1 AND f2 = v2 AND f3 = v3 OK

u2022 WHERE f1 = v1 AND f3 = v3 Not recommended (gap)

Provide me URLs for thread where it has been proven that above is useless and incorrect!

Regards,

Naveen.I

Read only

0 Likes
1,598

Please provide SAP documentation that shows this is correct.

Rob

Read only

0 Likes
1,598

Ok, Naveen, let's go...

> On OR Statement

> In some cases, it can be beneficial to simplify the WHERE conditions used on a LOOP iterator. For example, if you have several conditions that check the same field against a set of values using OR operators, it can be beneficial to place the conditions in a RANGE or SELECT-OPTION object and change the WHERE clause to: WHERE field IN [range] | [select-option]. The IN can be processed faster than several conditional statements joined by an OR (assuming you are using the same field as an operator). Example:

> GOOD: u2026 WHERE field1 IN range1.

> NOT AS GOOD: u2026 WHERE field1 = v1 OR field1 = v2 OR field1 = v3 OR field1 = v4.

This is absolutely the same. There is no single reason why IN list should be faster than OR. Wasted time for changing the code.

> On For All Entries

> When using the FOR ALL ENTRIES clause, performance can be improved by increasing the blocking factor. Since the FOR ALL ENTRIES clause essentially breaks down a table of records to be read into individual requests, the blocking factor controls how many of those records are grouped into a single request to the database. The default blocking factor is 5. For example, if the FOR ALL ENTRIES table contains 100 entries and the default blocking factor is used, then 20 separate requests for 5 records each will be sent to the database. If the blocking factor is increased to 100, then only 1 request would be sent to the database to retrieve all 100 records. This reduces the overhead needed to retrieve the data. Be careful not to increase the blocking factor too high as it increases the length of the query and there are maximum limitations in the database that will generate a short-dump if exceeded. The following Oracle u201Chintu201D can be added to queries to increase the blocking factor to 100 for that specific query only: %_HINTS ORACLE '&min_in_blocking_factor 10&&max_in_blocking_factor 100&&min_blocking_factor 10&&max_blocking_factor 100&'. Note that this hint will only optimize database queries when the FOR ALL ENTRIES clause is used and there are at least 100 entries expected in the result set

If you carefully read my reply, I did not comment your statement regarding max_blocking_factor. Indeed it can help in many cases.

> On Index

> Whenever possible, provide all fields in the primary key or index in the WHERE clause without gaps. Itu2019s OK to leave a field off at the end of the primary key or index, but gaps within the primary key or index should be avoided. For example, if an index is comprised of f1, f2, f3 and f4, then the following applies:

> u2022 WHERE f1= v1 AND f2 = v2 AND f3 = v3 AND f4 = v4 OK

> u2022 WHERE f1=v1 AND f2 = v2 AND f3 = v3 OK

> u2022 WHERE f1 = v1 AND f3 = v3 Not recommended (gap)

>

Sure this is correct, but it's so obvious that almost nobody is mentioning this stuff in this forum anymore. It can be found in thousands of places in Internet. It's like common sense.

And well, there is a little difference to what you have said before. Let me remind you...

> F2, F3, F4 = Using this in SELECT triggers index

Don't you see the "gap" at field1? So your original "advice" was incorrect as I already mentioned.

And believe me, I am doing performance optimizations for many SAP customers for the last 7 years. If somebody tells me something new, I always ask for the technical explanation (because as the end of the day the customer will ask me why did I advise something like this?). Without the technical explanation why certain thing is faster than another one, I don't trust anyone.

Kind regards,

Yuri

Read only

Former Member
0 Likes
1,598

How much entries does your IT_MATNR host?

If it´s around thousand or less you could make yourself a range table of MATNR for instance.

Read only

Former Member
0 Likes
1,598

there was an old recommendation to change ORs into IN-list (no ranges but IN (a, b, ...) programmed. I do not know whether this is still valid.

>F1, F2, F3 = using this in SELECT query triggers index

>F2, F3, F4 = Using this in SELECT triggers index

>F1, F2, F3, F4 = Also triggers Index

>F1, F3, F4 = Never triggers index as was broken at F2

Only option 3 is correct, if the key is the primary key, because this is unique

All others depend on costs and available other indexes.

Option 2 is a misinterpretation of the Oracle skip scan: Works only if different values for f1 are small and only for Oracle.

Option 4 again assums low selectivity for F1, because it would work fine, if the selectivity of f1 is high.

Replacing joins by FAE was discussed often ... the solution is 'it depends'.

Changing blocking factor - either generally or with a hint - is not recommended. This should only be done, if it is absolutely clear, how the statement is used (size of table, size of driver can normally vary a lot)

Read only

0 Likes
1,598

Hi,

this is the real fun with modern databases. They are so clever...

This is an example from my toy-around 11g babe:


SQL> select * from emp where empno=7369 or empno=7900;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK           7902 17-DEC-80        800                    20
      7900 JAMES      CLERK           7698 03-DEC-81        950                    30

---------------------------------------------------------------------------------------
| Id  | Operation                    | Name   | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT             |        |     2 |    64 |     2   (0)| 00:00:01 |
|   1 |  INLIST ITERATOR             |        |       |       |            |          |
|   2 |   TABLE ACCESS BY INDEX ROWID| EMP    |     2 |    64 |     2   (0)| 00:00:01 |
|*  3 |    INDEX UNIQUE SCAN         | PK_EMP |     2 |       |     1   (0)| 00:00:01 |
---------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   3 - access("EMPNO"=7369 OR "EMPNO"=7900)

Statistics
----------------------------------------------------------
          1  recursive calls
          0  db block gets
          4  consistent gets
          1  physical reads
          0  redo size
        939  bytes sent via SQL*Net to client
        420  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          2  rows processed

SQL>

I feel the need to pad on it's back mumbeling "good boy".

So the DB decides for an inlist iteration if you provide OR clauses on the same column.

Since some time you can not even override this with a use_concat hint any more.

The hint is still there, but does not seem to work when the same column is "OR"ed.

So the statement is in fact not transformed to a different plan any more,

unless you are still using a very old version.

Volker

Read only

yuri_ziryukin
Product and Topic Expert
Product and Topic Expert
0 Likes
1,598

Excellent, thanks for the confirmation, Volker.