Indexing of table LTAP - Performance of LT27 improved / but LT22 decreased

Hi all,
We had a performance issue with LT27 , so to overcome it we created indexing for the related fields in table LTAP.
The performance improved a lot. But recently we received a complaint from client that the performance of LT22 has reduced a lot . For both the programs the table used is LTAP,
The indexes are totally different as for LT22 using fields  LGNUM, VLTYP, VLPLA and PQUIT  and for LT27 the field used is is VLENR. The LT22 program uses LDB -  T3L .
My question is - will the performance of the other associated program which uses Table LTAP reduces due to creation of new index for LT27, EVENTHO
UGH  we are using different fields.
Please guide.
Thanks,
Venbgal Rao.
Moderator message - Moved to the correct forum
Edited by: Rob Burbank on Nov 18, 2009 9:38 AM

Hi,
The program used is LDB ( SAPDBT3L )  and the code is
A)   SELECT (LTAP_FIELDS-FIELDS) FROM LTAP
          INTO CORRESPONDING FIELDS OF TABLE ILTAP PACKAGE SIZE MAX_LTAP
            WHERE LGNUM = T3_LGNUM
            AND ( NLTYP IN INLTYP AND NLPLA IN INLPLA )
            AND PQUIT IN PQUIT
            AND (LTAP_SEL-WHERE_TAB).
          SORT ILTAP.                      "n_586127
          PERFORM ILTAP_AUSWERTEN.
        ENDSELECT.
B)   The secondary index details:
The table used is LTAP and the details of the fields in SECONDARY INDEX in the table is given in below sequence.
1)  LGNUM
2)  NLTYP
3)  NLPLA
4)  PQUIT
Hope this information will help u to suggest me a solution.
Thanks,
Vengal Rao

Similar Messages

  • Is Index organization tables better in performance compare to normal tables

    Hi,
    i am using oracle 10g and my domain is on telecom.
    my requirement is when 'A' party calls 'B' Party based on 'B' party number
    we have to find which area the call lands based on that tariff will be applied
    but the data configured in Area table is not the complete number its just a CC+NDC(4or5 digits in length)
    so i have to find which one matches the nearest to 'B' party number.
    i uses the following query
    select max(area_code)
    from ZONE_AREA
    where '9888123456' like AREA_CODE||'%'
    and network_id=1;
    this is the structure of the table
    create table ZONE_AREA(
    AREA_CODE VARCHAR2(20),
    AREA_NAME VARCHAR2(30) not null,
    ZONE_CODE VARCHAR2(10) not null,
    CALL_TYPE VARCHAR2(1) not null,
    NETWORK_ID NUMBER(2),
    primary key (NETWORK_ID, AREA_CODE))
    the table contains around 200000 rows.
    the data in table look like
    AREA_CODE
    98812
    90020
    900
    9732
    the hit ratio for the above query is massive since it fires for every call but my DBA complaining me
    this query utilizes more CPU need to be tuned.
    i thought of going for Index organization tables since i never used this but want to give a try to see any improvisation is there
    Hence i created the Index organization table(IOT) for the same above structure in my development environment
    with 60,000 rows in it.
    create table ZONE_AREA_IOT
    AREA_CODE VARCHAR2(20),
    AREA_NAME VARCHAR2(30) not null,
    ZONE_CODE VARCHAR2(10) not null,
    CALL_TYPE VARCHAR2(1) not null,
    NETWORK_ID NUMBER(2),
    CONSTRAINT pk_admin_docindex1 PRIMARY KEY (NETWORK_ID, AREA_CODE))
    ORGANIZATION INDEX
    also the plain table (ZONE_AREA) have 60,000 rows in my development server.
    now i fired the query on my plain table
    select max(area_code)
    from ZONE_AREA
    where '9888123456' like AREA_CODE||'%'
    and network_id=1;
    the following is the execution plan
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    | 0 | SELECT STATEMENT | | 1 | 11 | 3 (34)| 00:00:01 |
    | 1 | SORT AGGREGATE | | 1 | 11 | | |
    | 2 | FIRST ROW | | 1 | 11 | 3 (34)| 00:00:01 |
    |* 3 | INDEX RANGE SCAN (MIN/MAX)| SYS_C007738 | 1 | 11 | 3 (34)| 00:00:01 |
    now i fired the query on the newly created IOT table
    select max(area_code)
    from ZONE_AREA_IOT
    where '9888123456' like AREA_CODE||'%'
    and network_id=1;
    | Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
    | 0 | SELECT STATEMENT | | 1 | 25 | 2 (0)| 00:00:01 |
    | 1 | SORT AGGREGATE | | 1 | 25 | | |
    | 2 | FIRST ROW | | 21 | 525 | 2 (0)| 00:00:01 |
    |* 3 | INDEX RANGE SCAN (MIN/MAX)| PK_ADMIN_DOCINDEX1 | 21 | 525 | 2 (0)| 00:00:01 |
    both tables have similar record count
    but the plans differ don't under stand the Rows column in the above plans for normal table its shows 11 bytes
    for IOT table it shows 525 bytes why this difference ?
    also CPU cost shows 3 in normal table and for IOT it shows 2
    for the above scenario is IOT table is advisable will it cut down the CPU cost is any overheads there for using IOT
    please respond
    regards
    naveen

    I think you are deviating from the real problem.
    I'm also in Telecom domain and what you are talking about is what is called "most matching" algorithm.
    Practically suppose that party A calls party B and you want to know which is the tariff to apply.
    Usually tariff tables are based on this "most matching" criteria where the correct tariff is the most matching with the called number.
    Let me give you an example.
    Suppose that I have a tariff table in this way:
    WITH mytariff AS
       SELECT '90123' destination, 1.5 tariff_per_min FROM DUAL UNION ALL
       SELECT '9012'  destination, 1.6 tariff_per_min FROM DUAL UNION ALL
       SELECT '901'   destination, 1.7 tariff_per_min FROM DUAL UNION ALL
       SELECT '90'    destination, 1.8 tariff_per_min FROM DUAL UNION ALL
       SELECT '55123' destination, 1.0 tariff_per_min FROM DUAL UNION ALL
       SELECT '5512'  destination, 1.1 tariff_per_min FROM DUAL UNION ALL
       SELECT '551'   destination, 1.2 tariff_per_min FROM DUAL UNION ALL
       SELECT '55'    destination, 1.3 tariff_per_min FROM DUAL
    SELECT * FROM mytariff;
    DESTINATION          TARIFF_PER_MIN
    90123                           1.5
    9012                            1.6
    901                             1.7
    90                              1.8
    55123                             1
    5512                            1.1
    551                             1.2
    55                              1.3
    {code}
    Correct me if I'm wrong:
    {code}
    if party A dials 901234567 then it will match destination 90123 and tariff_per_min 1.5
    if party A dials 901244567 then it will match destination 9012  and tariff_per_min 1.6
    if party A dials 901344567 then it will match destination 901   and tariff_per_min 1.6
    if party A dials 551244567 then it will match destination 5512  and tariff_per_min 1.1
    etc.
    {code}
    Confirm if this is your criteria in finding the tariff.
    The billing/rating systems I know usually store this information in database tables but the rating engine (generally a c++ program in Unix) is normally reading this information once, putting them in memory and rating the calls by reading information in memory.
    I'm not saying that this is the only approach but it seems the most used.
    In your case, It looks that you are using to do the same thing SQL or PL/SQL and definitely I understand that applying this algorithm by reading the tariff table for each call records is going to affect your performances heavily.
    I have a couple of questions for your:
    1) Are you using a SQL statement or a PL/SQL procedure to rate your calls?
    2) Could you show us how you assign the tariff to your calls?
    I don't think using IOT will solve your problem. IOT has the advantage to read the data together with the index and it is suitable especially if you read your data always with a certain key.
    If your data about tariff is static, or doesn't change so often, which I suppose it the case, you could consider a different approach like loading them in a collection in PL/SQL and them retrieving them from collection. It might not be the optimal solution but it is worth considering it.
    In order to evaluate your problem please give the details mentioned above.
    Regards.
    Al                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               

  • Performance - table LTAP

    SAP 4.7 6.20 ORACLE 10G  WINDOWS SERVER 2008
    I have several selects to table LTAB which seem to be very slow.
    The clause of this select is : where MANDT = A0 and LGNUM = A1 and TANUM in (A2, A3, A4, A5, A6).
    In sm66 it's in sequential read, and in st04 it's using INDEX RANGE SCAN LTAP~M which is an SAP index.
    This index is by : MANDT, LGNUM, PQUIT, MATNR.
    And the slow programs are standard.
    But the keys of the table are : MANDT, LGNUM, TANUM, TAPOS, so I don't understand why it's using the index instead of reading by the own table.
    Sometimes I see in sm66 4, 5 programs accessing this table with this select at the same time, and it takes some time for them to disappear.
    And I don't understand why.
    Does anybody have a clue ?
    Eduardo

    Hi,
    SAP Note 191492 - Performance: Customer developments in MM/WM has a question about this table.
    If the problem is in an standard report, search notes, surely it's an error or performance note. It's sure if you have applied recently support-packages or you are using this functionality since a recent time. If you don't find it, send a message to SAP. Check  Note 67739 - Priorities of problem messages.
    Regards,
    Eduardo

  • 5 tables Used - Performance Improvement Help Req...

    Hello Experts,
    I am using 5 table joins to fetch data from query; does this will degrade performance?
    Please find below the query used; in this WHERE Clause, 1) le.locker_entry_id is PRIMARY Key column
    2) dc.object_type - created a index on this column 3) Created a function based index on this column upper(dt.partner_device_type)
    Can any other code improvement be done or view be created ?
    Please suggest.
    SELECT count(*) FROM locker_entry le;
    COUNT(*)              
    1762                  
    SELECT count(*) FROM digital_compatibility dc;
    COUNT(*)              
    227757    
    SELECT count(*) FROM digital_encode_profile dep;
    COUNT(*)              
    48                    
    SELECT count(*) FROM device_type dt;
    COUNT(*)              
    421                   
    SELECT count(*) FROM digital_sku dsku;
    COUNT(*)              
    26037     
    EXPLAIN PLAN FOR
    SELECT
      /*+ INDEX(dep, DIGITAL_ENCODE_PROFILE_ID_PK) */
      DISTINCT le.locker_entry_id AS locker_entry_id,
      dep.delivery_type
    FROM locker_entry le,
      digital_compatibility dc,
      digital_encode_profile dep,
      device_type dt,
      digital_sku dsku
    WHERE le.sku_id                   = dsku.legacy_id
    AND le.digital_package_id         = dsku.digital_package_id
    AND dsku.digital_sku_id           = dc.object_id
    AND dc.encode_profile_id          =dep.digital_encode_profile_id
    AND dt.capability_set_id          =dc.capability_set_id
    AND le.locker_entry_id           IN (:1, :2, :3, :4, :5, :6, :7, :8, :9, :10, :11, :12, :13, :14, :15, :16, :17, :18, :19, :20, :21, :22, :23, :24, :25, :26, :27, :28, :29, :30, :31, :32)
    AND dc.object_type                =:"SYS_B_0"
    AND upper(dt.partner_device_type) =:33;
    SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
    | Id  | Operation                             | Name                         | Rows  | Bytes | Cost (%CPU)|
    |   0 | SELECT STATEMENT                      |                              |     1 |   370 |   481   (3)|
    |   1 |  HASH UNIQUE                          |                              |     1 |   370 |   481   (3)|
    |   2 |   NESTED LOOPS                        |                              |     1 |   370 |   480   (3)|
    |   3 |    NESTED LOOPS                       |                              |     1 |   336 |   479   (3)|
    |*  4 |     HASH JOIN                         |                              |     1 |   193 |   478   (3)|
    |   5 |      MAT_VIEW ACCESS BY INDEX ROWID   | DIGITAL_SKU                  |     1 |    48 |     5   (0)|
    |   6 |       NESTED LOOPS                    |                              |    16 |  1392 |     5   (0)|
    |   7 |        INLIST ITERATOR                |                              |       |       |            |
    |   8 |         TABLE ACCESS BY INDEX ROWID   | LOCKER_ENTRY                 |    32 |  1248 |     1   (0)|
    |*  9 |          INDEX RANGE SCAN             | LOCKER_ENTRY_ID_PK           |    32 |       |     1   (0)|
    |  10 |        BITMAP CONVERSION TO ROWIDS    |                              |       |       |            |
    |  11 |         BITMAP AND                    |                              |       |       |            |
    |  12 |          BITMAP CONVERSION FROM ROWIDS|                              |       |       |            |
    |* 13 |           INDEX RANGE SCAN            | IDX_DIGITAL_SKU_LEGACY_ID    |     1 |       |     1   (0)|
    |  14 |          BITMAP CONVERSION FROM ROWIDS|                              |       |       |            |
    |* 15 |           INDEX RANGE SCAN            | IDX_DIGITAL_PACKAGE_ID       |     1 |       |     1   (0)|
    |* 16 |      MAT_VIEW ACCESS FULL             | DIGITAL_COMPATIBILITY        |  2098 |   217K|   472   (3)|
    |* 17 |     INDEX RANGE SCAN                  | DEVICE_TYPE_IDX              |     1 |   143 |     1   (0)|
    |  18 |    MAT_VIEW ACCESS BY INDEX ROWID     | DIGITAL_ENCODE_PROFILE       |     1 |    34 |     1   (0)|
    |* 19 |     INDEX UNIQUE SCAN                 | DIGITAL_ENCODE_PROFILE_ID_PK |     1 |       |     1   (0)|
    Predicate Information (identified by operation id):
       4 - access("DSKU"."DIGITAL_SKU_ID"=TO_NUMBER("DC"."OBJECT_ID"))
       9 - access("LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:1) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:2) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:3) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:4) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:5) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:6) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:7) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:8) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:9) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:10) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:11) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:12) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:13) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:14) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:15) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:16) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:17) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:18) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:19) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:20) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:21) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:22) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:23) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:24) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:25) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:26) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:27) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:28) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:29) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:30) OR
                  "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:31) OR "LE"."LOCKER_ENTRY_ID"=TO_NUMBER(:32))
      13 - access("LE"."SKU_ID"="DSKU"."LEGACY_ID")
      15 - access("LE"."DIGITAL_PACKAGE_ID"="DSKU"."DIGITAL_PACKAGE_ID")
      16 - filter("DC"."OBJECT_TYPE"=:SYS_B_0)
      17 - access("DT"."CAPABILITY_SET_ID"="DC"."CAPABILITY_SET_ID" AND
                  UPPER("PARTNER_DEVICE_TYPE")=:33)
      19 - access("DC"."ENCODE_PROFILE_ID"="DEP"."DIGITAL_ENCODE_PROFILE_ID")
    Note
       - 'PLAN_TABLE' is old version
    Trace information
    =================  
    recursive calls     17
    db block gets     0
    consistent gets     239
    physical reads     61
    redo size     0
    bytes sent via SQL*Net to client     742
    bytes received via SQL*Net from client     1361
    SQL*Net roundtrips to/from client     2
    sorts (memory)     5
    sorts (disk)     0
       Edited by: Linus on Oct 10, 2011 2:44 AM

    Linus wrote:
    Yes Bravid i got regarding the point to remove the hint from the query; unless there is a change in execution plan with index hint.
    My concern is; is there any issues by keeping 5 tables on single query and will this degrade performance?
    Because as of during the certification practise; i used to overcome some where ,"NOT to use many table joins".
    So that is reason i am asking you; sorry if am wrong in any ways.
    Thanks...There's nothing inherently wrong with joining lots of tables and there isn't one specific thing that will degrade performance. You could have a query that joins 2 tables performing very badly and a query with 10 tables that performs very well. A lot of it is down to the quality of the decisions the optimiser can make. To get the best decisions out of it you need to make sure it had enough information to work with. So that means making sure stats are available and relevant for the data you're querying and removing any hints unless you have a specific reason to use them.
    Earlier this year I had the "joy" of working with a query that had 65 tables in it. It was an INSERT INTO...SELECT FROM and it was a clear example of where a single statement really should have been about 6 or 7 separate statements. The reason in this case was because there were 6 or 7 different sections to the query that had essentially no relationship with each other and they were all outer joined and used lots of analytic functions and case statements to categorise each row and populate the same columns with different values depending on which query block it had originated from.
    This is an extreme example but the point is you have to look at the statement and decide whether it does it's job well. My personal preference is to try to avoid big "generic" SQL statements that cater for lots of different scenarios because they can easily become over complicated and difficult to maintain and tune.
    HTH
    David
    Edited by: Bravid on Oct 10, 2011 1:53 PM

  • When table with clustered columnstore indexe is partitioned the performance degrades if data is located in multiple partitions

    Hello,
    Below I provide a complete code to re-produce the behavior I am observing.  You could run it in tempdb or any other database, which is not important.  The test query provided at the top of the script is pretty silly, but I have observed the same
    performance degradation with about a dozen of various queries of different complexity, so this is just the simplest one I am using as an example here. Note that I also included approximate run times in the script comments (this is obviously based on what I
    observed on my machine).  Here are the steps with numbers corresponding to the numbers in the script:
    1. Run script from #1 to #7.  This will create the two test tables, populate them with records (40 mln. and 10 mln.) and build regular clustered indexes.
    2. Run test query (at the top of the script).  Here are the execution statistics:
    Table 'Main'. Scan count 5, logical reads 151435, physical reads 0, read-ahead reads 4, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Txns'. Scan count 5, logical reads 74155, physical reads 0, read-ahead reads 7, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
     SQL Server Execution Times:
       CPU time = 5514 ms, 
    elapsed time = 1389 ms.
    3. Run script from #8 to #9. This will replace regular clustered indexes with columnstore clustered indexes.
    4. Run test query (at the top of the script).  Here are the execution statistics:
    Table 'Txns'. Scan count 4, logical reads 44563, physical reads 0, read-ahead reads 37186, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Main'. Scan count 4, logical reads 54850, physical reads 2, read-ahead reads 96862, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
     SQL Server Execution Times:
       CPU time = 828 ms, 
    elapsed time = 392 ms.
    As you can see the query is clearly faster.  Yay for columnstore indexes!.. But let's continue.
    5. Run script from #10 to #12 (note that this might take some time to execute).  This will move about 80% of the data in both tables to a different partition.  You should be able to see the fact that the data has been moved when running Step #
    11.
    6. Run test query (at the top of the script).  Here are the execution statistics:
    Table 'Txns'. Scan count 4, logical reads 44563, physical reads 0, read-ahead reads 37186, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Main'. Scan count 4, logical reads 54817, physical reads 2, read-ahead reads 96862, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
     SQL Server Execution Times:
       CPU time = 8172 ms, 
    elapsed time = 3119 ms.
    And now look, the I/O stats look the same as before, but the performance is the slowest of all our tries!
    I am not going to paste here execution plans or the detailed properties for each of the operators.  They show up as expected -- column store index scan, parallel/partitioned = true, both estimated and actual number of rows is less than during the second
    run (when all of the data resided on the same partition).
    So the question is: why is it slower?
    Thank you for any help!
    Here is the code to re-produce this:
    --==> Test Query - begin --<===
    DBCC DROPCLEANBUFFERS
    DBCC FREEPROCCACHE
    SET STATISTICS IO ON
    SET STATISTICS TIME ON
    SELECT COUNT(1)
    FROM Txns AS z WITH(NOLOCK)
    LEFT JOIN Main AS mmm WITH(NOLOCK) ON mmm.ColBatchID = 70 AND z.TxnID = mmm.TxnID AND mmm.RecordStatus = 1
    WHERE z.RecordStatus = 1
    --==> Test Query - end --<===
    --===========================================================
    --1. Clean-up
    IF OBJECT_ID('Txns') IS NOT NULL DROP TABLE Txns
    IF OBJECT_ID('Main') IS NOT NULL DROP TABLE Main
    IF EXISTS (SELECT 1 FROM sys.partition_schemes WHERE name = 'PS_Scheme') DROP PARTITION SCHEME PS_Scheme
    IF EXISTS (SELECT 1 FROM sys.partition_functions WHERE name = 'PF_Func') DROP PARTITION FUNCTION PF_Func
    --2. Create partition funciton
    CREATE PARTITION FUNCTION PF_Func(tinyint) AS RANGE LEFT FOR VALUES (1, 2, 3)
    --3. Partition scheme
    CREATE PARTITION SCHEME PS_Scheme AS PARTITION PF_Func ALL TO ([PRIMARY])
    --4. Create Main table
    CREATE TABLE dbo.Main(
    SetID int NOT NULL,
    SubSetID int NOT NULL,
    TxnID int NOT NULL,
    ColBatchID int NOT NULL,
    ColMadeId int NOT NULL,
    RecordStatus tinyint NOT NULL DEFAULT ((1))
    ) ON PS_Scheme(RecordStatus)
    --5. Create Txns table
    CREATE TABLE dbo.Txns(
    TxnID int IDENTITY(1,1) NOT NULL,
    GroupID int NULL,
    SiteID int NULL,
    Period datetime NULL,
    Amount money NULL,
    CreateDate datetime NULL,
    Descr varchar(50) NULL,
    RecordStatus tinyint NOT NULL DEFAULT ((1))
    ) ON PS_Scheme(RecordStatus)
    --6. Populate data (credit to Jeff Moden: http://www.sqlservercentral.com/articles/Data+Generation/87901/)
    -- 40 mln. rows - approx. 4 min
    --6.1 Populate Main table
    DECLARE @NumberOfRows INT = 40000000
    INSERT INTO Main (
    SetID,
    SubSetID,
    TxnID,
    ColBatchID,
    ColMadeID,
    RecordStatus)
    SELECT TOP (@NumberOfRows)
    SetID = ABS(CHECKSUM(NEWID())) % 500 + 1, -- ABS(CHECKSUM(NEWID())) % @Range + @StartValue,
    SubSetID = ABS(CHECKSUM(NEWID())) % 3 + 1,
    TxnID = ABS(CHECKSUM(NEWID())) % 1000000 + 1,
    ColBatchId = ABS(CHECKSUM(NEWID())) % 100 + 1,
    ColMadeID = ABS(CHECKSUM(NEWID())) % 500000 + 1,
    RecordStatus = 1
    FROM sys.all_columns ac1
    CROSS JOIN sys.all_columns ac2
    --6.2 Populate Txns table
    -- 10 mln. rows - approx. 1 min
    SET @NumberOfRows = 10000000
    INSERT INTO Txns (
    GroupID,
    SiteID,
    Period,
    Amount,
    CreateDate,
    Descr,
    RecordStatus)
    SELECT TOP (@NumberOfRows)
    GroupID = ABS(CHECKSUM(NEWID())) % 5 + 1, -- ABS(CHECKSUM(NEWID())) % @Range + @StartValue,
    SiteID = ABS(CHECKSUM(NEWID())) % 56 + 1,
    Period = DATEADD(dd,ABS(CHECKSUM(NEWID())) % 365, '05-04-2012'), -- DATEADD(dd,ABS(CHECKSUM(NEWID())) % @Days, @StartDate)
    Amount = CAST(RAND(CHECKSUM(NEWID())) * 250000 + 1 AS MONEY),
    CreateDate = DATEADD(dd,ABS(CHECKSUM(NEWID())) % 365, '05-04-2012'),
    Descr = REPLICATE(CHAR(65 + ABS(CHECKSUM(NEWID())) % 26), ABS(CHECKSUM(NEWID())) % 20),
    RecordStatus = 1
    FROM sys.all_columns ac1
    CROSS JOIN sys.all_columns ac2
    --7. Add PK's
    -- 1 min
    ALTER TABLE Txns ADD CONSTRAINT PK_Txns PRIMARY KEY CLUSTERED (RecordStatus ASC, TxnID ASC) ON PS_Scheme(RecordStatus)
    CREATE CLUSTERED INDEX CDX_Main ON Main(RecordStatus ASC, SetID ASC, SubSetId ASC, TxnID ASC) ON PS_Scheme(RecordStatus)
    --==> Run test Query --<===
    --===========================================================
    -- Replace regular indexes with clustered columnstore indexes
    --===========================================================
    --8. Drop existing indexes
    ALTER TABLE Txns DROP CONSTRAINT PK_Txns
    DROP INDEX Main.CDX_Main
    --9. Create clustered columnstore indexes (on partition scheme!)
    -- 1 min
    CREATE CLUSTERED COLUMNSTORE INDEX PK_Txns ON Txns ON PS_Scheme(RecordStatus)
    CREATE CLUSTERED COLUMNSTORE INDEX CDX_Main ON Main ON PS_Scheme(RecordStatus)
    --==> Run test Query --<===
    --===========================================================
    -- Move about 80% the data into a different partition
    --===========================================================
    --10. Update "RecordStatus", so that data is moved to a different partition
    -- 14 min (32002557 row(s) affected)
    UPDATE Main
    SET RecordStatus = 2
    WHERE TxnID < 800000 -- range of values is from 1 to 1 mln.
    -- 4.5 min (7999999 row(s) affected)
    UPDATE Txns
    SET RecordStatus = 2
    WHERE TxnID < 8000000 -- range of values is from 1 to 10 mln.
    --11. Check data distribution
    SELECT
    OBJECT_NAME(SI.object_id) AS PartitionedTable
    , DS.name AS PartitionScheme
    , SI.name AS IdxName
    , SI.index_id
    , SP.partition_number
    , SP.rows
    FROM sys.indexes AS SI WITH (NOLOCK)
    JOIN sys.data_spaces AS DS WITH (NOLOCK)
    ON DS.data_space_id = SI.data_space_id
    JOIN sys.partitions AS SP WITH (NOLOCK)
    ON SP.object_id = SI.object_id
    AND SP.index_id = SI.index_id
    WHERE DS.type = 'PS'
    AND OBJECT_NAME(SI.object_id) IN ('Main', 'Txns')
    ORDER BY 1, 2, 3, 4, 5;
    PartitionedTable PartitionScheme IdxName index_id partition_number rows
    Main PS_Scheme CDX_Main 1 1 7997443
    Main PS_Scheme CDX_Main 1 2 32002557
    Main PS_Scheme CDX_Main 1 3 0
    Main PS_Scheme CDX_Main 1 4 0
    Txns PS_Scheme PK_Txns 1 1 2000001
    Txns PS_Scheme PK_Txns 1 2 7999999
    Txns PS_Scheme PK_Txns 1 3 0
    Txns PS_Scheme PK_Txns 1 4 0
    --12. Update statistics
    EXEC sys.sp_updatestats
    --==> Run test Query --<===

    Hello Michael,
    I just simulated the situation and got the same results as in your description. However, I did one more test - I rebuilt the two columnstore indexes after the update (and test run). I got the following details:
    Table 'Txns'. Scan count 8, logical reads 12922, physical reads 1, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Main'. Scan count 8, logical reads 57042, physical reads 1, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Workfile'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    Table 'Worktable'. Scan count 0, logical reads 0, physical reads 0, read-ahead reads 0, lob logical reads 0, lob physical reads 0, lob read-ahead reads 0.
    SQL Server Execution Times:
    CPU time = 251 ms, elapsed time = 128 ms.
    As an explanation of the behavior - because of the UPDATE statement in CCI is executed as a DELETE and INSERT operation, you had all original row groups of the index with almost all data deleted and almost the same amount of new row groups with new data
    (coming from the update). I suppose scanning the deleted bitmap caused the additional slowness at your end or something related with that "fragmentation". 
    Ivan Donev MCITP SQL Server 2008 DBA, DB Developer, BI Developer

  • How can I use Indexed Temp tables to optimize performance?

    Instead of joining two CTEs together, I am now going to attempt to join two indexed temp tables. 
    The first temp table is a number of encounters that returns 147 rows in 2 seconds. The second temp table
    is progress notes for all those encounters returning 136 rows in 18 seconds. Joining the indexed views comes back at 3 1/2 minutes.
    What can I do to optimize performance?
    Code is below. Thanks in advance!
    if object_id('tempdb..#arpb') is not null begin drop table #arpb end;
    if object_id('tempdb..#progress_notes') is not null begin drop table #progress_notes end;
    SELECT DISTINCT
    ARPB.PAT_ENC_CSN_ID, ARPB.SERVICE_DATE, ARPB.BILLING_PROV_ID, ARPB.DEPARTMENT_ID,
    SER.PROV_NAME, DEP.DEPARTMENT_NAME, E.APPT_TIME, ZC_APPT.NAME AS APPT_STATUS
    INTO #arpb
    FROM ARPB_TRANSACTIONS ARPB
    LEFT OUTER JOIN CLARITY_SER AS SER ON SER.PROV_ID = ARPB.BILLING_PROV_ID
    LEFT OUTER JOIN CLARITY_DEP AS DEP ON DEP.DEPARTMENT_ID = ARPB.DEPARTMENT_ID
    LEFT OUTER JOIN PAT_ENC AS E ON E.PAT_ENC_CSN_ID = ARPB.PAT_ENC_CSN_ID
    LEFT OUTER JOIN ZC_APPT_STATUS AS ZC_APPT ON ZC_APPT.APPT_STATUS_C = E.APPT_STATUS_C
    WHERE ARPB.DEPARTMENT_ID = xxxx
    AND ARPB.TX_TYPE_C = 1
    AND ARPB.VOID_DATE IS NULL
    AND ARPB.BILLING_PROV_ID = xxxx
    AND ARPB.SERVICE_DATE BETWEEN
    'xxxx' AND 'xxxxx'
    create clustered index idx_temp_arpb on #arpb(PAT_ENC_CSN_ID)
    SELECT DISTINCT
    ARPB.PAT_ENC_CSN_ID,
    ZCNT.NAME AS NOTE_TYPE, PR.NAME AS PURPOSE, HNO_INFO.NOTE_ID,
    EMP.NAME AS EMP_NAME, STS.NAME AS NOTE_STATUS
    INTO #progress_notes
    FROM ARPB_TRANSACTIONS ARPB
    LEFT OUTER JOIN ENC_NOTE_INFO AS ENC_NOTE_INFO ON ARPB.PAT_ENC_CSN_ID = ENC_NOTE_INFO.PAT_ENC_CSN_ID
    LEFT OUTER JOIN HNO_INFO AS HNO_INFO ON ENC_NOTE_INFO.ENCOUNTER_NOTE_ID = HNO_INFO.NOTE_ID
    LEFT OUTER JOIN ZC_NOTE_TYPE AS ZCNT ON ZCNT.NOTE_TYPE_C = ENC_NOTE_INFO.NOTE_TYPE_C
    LEFT OUTER JOIN ZC_NOTE_PURPOSE AS PR ON PR.NOTE_PURPOSE_C = HNO_INFO.NOTE_PURPOSE_C
    LEFT OUTER JOIN CLARITY_EMP AS EMP ON EMP.EPIC_EMP_ID = HNO_INFO.CURRENT_AUTHOR_ID
    LEFT OUTER JOIN ZC_NOTE_STATUS AS STS ON STS.NOTE_STATUS_C = ENC_NOTE_INFO.NOTE_STATUS_C
    WHERE ARPB.DEPARTMENT_ID = xxxx
    AND ARPB.TX_TYPE_C = 1
    AND ARPB.VOID_DATE IS NULL
    AND ARPB.BILLING_PROV_ID = xxxx
    AND ZCNT.NAME = 'xxxx'
    AND ARPB.SERVICE_DATE BETWEEN
    'xxxx' AND 'xxxx'
    AND PR.NAME = 'xxxxx'
    create index idx_temp_pn on #progress_notes(PAT_ENC_CSN_ID)
    SELECT
    #arpb.PAT_ENC_CSN_ID,
    #arpb.APPT_TIME,
    #arpb.SERVICE_DATE,
    #arpb.BILLING_PROV_ID,
    #arpb.PROV_NAME,
    #arpb.DEPARTMENT_ID,
    #arpb.DEPARTMENT_NAME,
    #progress_notes.EMP_NAME as NoteEmp,
    CASE #progress_notes.NOTE_ID
    WHEN null THEN 'No Progress Note'
    ELSE #progress_notes.NOTE_ID
    END as NoteId,
    #progress_notes.NOTE_STATUS,
    #progress_notes.NOTE_TYPE,
    #progress_notes.PURPOSE
    FROM #ARPB
    LEFT JOIN #PROGRESS_NOTES ON #ARPB.PAT_ENC_CSN_ID = #PROGRESS_NOTES.PAT_ENC_CSN_ID
    To err is human, to REALLY foul things up requires a computer

    Something is not right here. What is the type of that column in both temp tables?
    I would assume that joining 147 and 136 rows should be done in less than 1 sec. even without indexes.
    How did you measure the time?
    BTW, I suggest to use aliases in your last query - it will be easier to read. Also use COALESCE function instead of CASE for the Note_ID (BTW, is Note_ID a character column - otherwise you supposed to get an error).
    For every expert, there is an equal and opposite expert. - Becker's Law
    My blog
    My TechNet articles

  • Issue with index on table

    Hi,
    We have created an index(assume z2) on table CATSDB with 2 fields. There is an other index(Z1 assume) with the same fields and the order is also same. When a report accesing the table it is taking more time to run when index Z2 is on table. But when deleted then the report ran quickly. Is it with the duplicate index created???
    Please let me know
    Regards
    Shiva

    Hi
    i am giving total index and buffering concept details by seeing this you can understand how we can achive performance through these
    <b>reward if usefull</b>
    <b>Performance during table access</b>
    <b>Indexes</b>
    Primary and secondary indexes
    Structure of an index
    Accessing tables using indexes
    <b>Table buffering</b>
    Advantages of buffering
    Concept of buffering
    Buffering types
    Buffer synchronization
    <b>Primary and secondary indexes</b>
    Index: Technical key of a database table.
    Primary index: The primary index contains the key fields of the table and a pointer to the non-key fields of the table. The primary index is created automatically when the table is created in the database.
    Secondary index: Additional indexes could be created considering the most frequently accessed dimensions of the table.
    <b>Structure of an Index</b>
    An index can be used to speed up the selection of data records from a table.
    An index can be considered to be a copy of a database table reduced to certain fields. The data is stored in sorted form in this copy. This sorting permits fast access to the records of the table (for example using a binary search). Not all of the fields of the table are contained in the index. The index also contains a pointer from the index entry to the corresponding table entry to permit all the field contents to be read.
    When creating indexes, please note that:
    An index can only be used up to the last specified field in the selection! The fields which are specified in the WHERE clause for a large number of selections should be in the first position.
    Only those fields whose values significantly restrict the amount of data are meaningful in an index.
    When you change a data record of a table, you must adjust the index sorting. Tables whose contents are frequently changed therefore should not have too many indexes.
    Make sure that the indexes on a table are as disjunctive as possible.
    (That is they should contain as few fields in common as possible. If two indexes on a table have a large number of common fields, this could make it more difficult for the optimizer to choose the most selective index.)
    <b>Accessing tables using Indexes</b>
    The database optimizer decides which index on the table should be used by the database to access data records.
    You must distinguish between the primary index and secondary indexes of a table. The primary index contains the key fields of the table. The primary index is automatically created in the database when the table is activated. If a large table is frequently accessed such that it is not possible to apply primary index sorting, you should create secondary indexes for the table.
    The indexes on a table have a three-character index ID. '0' is reserved for the primary index. Customers can create their own indexes on SAP tables; their IDs must begin with Y or Z.
    If the index fields have key function, i.e. they already uniquely identify each record of the table, an index can be called a unique index. This ensures that there are no duplicate index fields in the database.
    When you define a secondary index in the ABAP Dictionary, you can specify whether it should be created on the database when it is activated. Some indexes only result in a gain in performance for certain database systems. You can therefore specify a list of database systems when you define an index. The index is then only created on the specified database systems when activated
    <b>Database access using Buffer concept</b>
    Buffering allows you to access data quicker by letting you
    access it from the application server instead of the database.
    <b>Advantages of buffering</b>
    Table buffering increases the performance when the records of the table are read.
    As records of a buffered table are read directly from the local buffer of the application server on which the accessing transaction is running, time required to access data is greatly reduced. The access improves by a factor of 10 to 100 depending on the structure of the table and on the exact system configuration.
    If the storage requirements in the buffer increase due to further data, the data that has not been accessed for the longest time is displaced. This displacement takes place asynchronously at certain times which are defined dynamically based on the buffer accesses. Data is only displaced if the free space in  the buffer is less than a predefined value or the quality of the access is not satisfactory at this time.
    Entering $TAB in the command field resets the table buffers on the corresponding application server. Only use this command if there are inconsistencies in the buffer. In large systems, it can take several hours to fill the buffers. The performance is considerably reduced during this time.
    <b>Concept of buffering</b>
    The R/3 System manages and synchronizes the buffers on the individual application servers. If an application program accesses data of a table, the database interfaces determines whether this data lies in the buffer of the application server. If this is the case, the data is read directly from the buffer. If the data is not in the buffer of the application server, it is read from the database and loaded into the buffer. The buffer can therefore satisfy the next access to this data.
    The buffering type determines which records of the table are loaded into the buffer of the application server when a record of the table is accessed. There are three different buffering types.
    With full buffering, all the table records are loaded into the buffer when one record of the table is accessed.
    With generic buffering, all the records whose left-justified part of the key is the same are loaded into the buffer when a table record is accessed.
    With single-record buffering, only the record that was accessed is loaded into the buffer.
    <b>Buffering types</b>
    With full buffering, the table is either completely or not at all in the buffer. When a record of the table is accessed, all the records of the table are loaded into the buffer.
    When you decide whether a table should be fully buffered, you must take the table size, the number of read accesses and the number of write accesses into consideration. The smaller the table is, the more frequently it is read and the less frequently it is written, the better it is to fully buffer the table.
    Full buffering is also advisable for tables having frequent accesses to records that do not exist. Since all the records of the table reside in the buffer, it is already clear in the buffer whether or not a record exists.
    The data records are stored in the buffer sorted by table key. When you access the data with SELECT, only fields up to the last specified key field can be used for the access. The left-justified part of the key should therefore be as large as possible for such accesses. For example, if the first key field is not defined, the entire table is scanned in the buffer. Under these circumstances, a direct access to the database could be more efficient if there is a suitable secondary index there.
    With generic buffering, all the records whose generic key fields agree with this record are loaded into the buffer when one record of the table is accessed. The generic key is a left-justified part of the primary key of the table that must be defined when the buffering type is selected. The generic key should be selected so that the generic areas are not too small, which would result in too many generic areas. If there are only a few records for each generic area, full buffering is usually preferable for the table. If you choose too large a generic key, too much data will be invalidated if there are changes to table entries, which would have a negative effect on the performance.
    A table should be generically buffered if only certain generic areas of the table are usually needed for processing.
    Client-dependent, fully buffered tables are automatically generically buffered. The client field is the generic key. It is assumed that not all of the clients are being processed at the same time on one application server. Language-dependent tables are a further example of generic buffering. The generic key includes all the key fields up to and including the language field.
    The generic areas are managed in the buffer as independent objects. The generic areas are managed analogously to fully buffered tables. You should therefore also read the information about full buffering.
    Single-record buffering is recommended particularly for large tables in which only a few records are accessed repeatedly with SELECT SINGLE. All the accesses to the table that do not use SELECT SINGLE bypass the buffer and directly access the database.
    If you access a record that was not yet buffered using SELECT SINGLE, there is a database access to load the record. If the table does not contain a record with the specified key, this record is recorded in the buffer as non-existent. This prevents a further database access if you make another access with the same key
    You only need one database access to load a table with full buffering, but you need several database accesses with single-record buffering. Full buffering is therefore generally preferable for small tables that are frequently accessed.
    <b>Synchronizing local buffers</b>
    The table buffers reside locally on each application server in the system. However, this makes it necessary for the buffer administration to transfer all changes made to buffered objects to all the application servers of the system.
    If a buffered table is modified, it is updated synchronously in the buffer of the application server from which the change was made. The buffers of the whole network, that is, the buffers of all the other application servers, are synchronized with an asynchronous procedure.
    Entries are written in a central database table (DDLOG) after each table modification that could be buffered. Each application server reads these entries at fixed time intervals.
    If entries are found that show a change to the data buffered by this server, this data is invalidated. If this data is accessed again, it is read directly from the database. In such an access, the table can then be loaded to the buffer again.

  • ABAP performance issues and improvements

    Hi All,
    Pl. give me the ABAP performance issue and improvement points.
    Regards,
    Hema

    Performance tuning for Data Selection Statement
    For all entries
    The for all entries creates a where clause, where all the entries in the driver table are combined with OR. If the number of
    entries in the driver table is larger than rsdb/max_blocking_factor, several similar SQL statements are executed to limit the
    length of the WHERE clause.
    The plus
    Large amount of data
    Mixing processing and reading of data
    Fast internal reprocessing of data
    Fast
    The Minus
    Difficult to program/understand
    Memory could be critical (use FREE or PACKAGE size)
    Some steps that might make FOR ALL ENTRIES more efficient:
    Removing duplicates from the the driver table
    Sorting the driver table
          If possible, convert the data in the driver table to ranges so a BETWEEN statement is used instead of and OR statement:
          FOR ALL ENTRIES IN i_tab
            WHERE mykey >= i_tab-low and
                  mykey <= i_tab-high.
    Nested selects
    The plus:
    Small amount of data
    Mixing processing and reading of data
    Easy to code - and understand
    The minus:
    Large amount of data
    when mixed processing isn’t needed
    Performance killer no. 1
    Select using JOINS
    The plus
    Very large amount of data
    Similar to Nested selects - when the accesses are planned by the programmer
    In some cases the fastest
    Not so memory critical
    The minus
    Very difficult to program/understand
    Mixing processing and reading of data not possible
    Use the selection criteria
    SELECT * FROM SBOOK.                   
      CHECK: SBOOK-CARRID = 'LH' AND       
                      SBOOK-CONNID = '0400'.        
    ENDSELECT.                             
    SELECT * FROM SBOOK                     
      WHERE CARRID = 'LH' AND               
            CONNID = '0400'.                
    ENDSELECT.                              
    Use the aggregated functions
    C4A = '000'.              
    SELECT * FROM T100        
      WHERE SPRSL = 'D' AND   
            ARBGB = '00'.     
      CHECK: T100-MSGNR > C4A.
      C4A = T100-MSGNR.       
    ENDSELECT.                
    SELECT MAX( MSGNR ) FROM T100 INTO C4A 
    WHERE SPRSL = 'D' AND                
           ARBGB = '00'.                  
    Select with view
    SELECT * FROM DD01L                    
      WHERE DOMNAME LIKE 'CHAR%'           
            AND AS4LOCAL = 'A'.            
      SELECT SINGLE * FROM DD01T           
        WHERE   DOMNAME    = DD01L-DOMNAME 
            AND AS4LOCAL   = 'A'           
            AND AS4VERS    = DD01L-AS4VERS 
            AND DDLANGUAGE = SY-LANGU.     
    ENDSELECT.                             
    SELECT * FROM DD01V                    
    WHERE DOMNAME LIKE 'CHAR%'           
           AND DDLANGUAGE = SY-LANGU.     
    ENDSELECT.                             
    Select with index support
    SELECT * FROM T100            
    WHERE     ARBGB = '00'      
           AND MSGNR = '999'.    
    ENDSELECT.                    
    SELECT * FROM T002.             
      SELECT * FROM T100            
        WHERE     SPRSL = T002-SPRAS
              AND ARBGB = '00'      
              AND MSGNR = '999'.    
      ENDSELECT.                    
    ENDSELECT.                      
    Select … Into table
    REFRESH X006.                 
    SELECT * FROM T006 INTO X006. 
      APPEND X006.                
    ENDSELECT
    SELECT * FROM T006 INTO TABLE X006.
    Select with selection list
    SELECT * FROM DD01L              
      WHERE DOMNAME LIKE 'CHAR%'     
            AND AS4LOCAL = 'A'.      
    ENDSELECT
    SELECT DOMNAME FROM DD01L    
    INTO DD01L-DOMNAME         
    WHERE DOMNAME LIKE 'CHAR%' 
           AND AS4LOCAL = 'A'.  
    ENDSELECT
    Key access to multiple lines
    LOOP AT TAB.          
    CHECK TAB-K = KVAL. 
    ENDLOOP.              
    LOOP AT TAB WHERE K = KVAL.     
    ENDLOOP.                        
    Copying internal tables
    REFRESH TAB_DEST.              
    LOOP AT TAB_SRC INTO TAB_DEST. 
      APPEND TAB_DEST.             
    ENDLOOP.                       
    TAB_DEST[] = TAB_SRC[].
    Modifying a set of lines
    LOOP AT TAB.             
      IF TAB-FLAG IS INITIAL.
        TAB-FLAG = 'X'.      
      ENDIF.                 
      MODIFY TAB.            
    ENDLOOP.                 
    TAB-FLAG = 'X'.                  
    MODIFY TAB TRANSPORTING FLAG     
               WHERE FLAG IS INITIAL.
    Deleting a sequence of lines
    DO 101 TIMES.               
      DELETE TAB_DEST INDEX 450.
    ENDDO.                      
    DELETE TAB_DEST FROM 450 TO 550.
    Linear search vs. binary
    READ TABLE TAB WITH KEY K = 'X'.
    READ TABLE TAB WITH KEY K = 'X' BINARY SEARCH.
    Comparison of internal tables
    DESCRIBE TABLE: TAB1 LINES L1,      
                    TAB2 LINES L2.      
    IF L1 <> L2.                        
      TAB_DIFFERENT = 'X'.              
    ELSE.                               
      TAB_DIFFERENT = SPACE.            
      LOOP AT TAB1.                     
        READ TABLE TAB2 INDEX SY-TABIX. 
        IF TAB1 <> TAB2.                
          TAB_DIFFERENT = 'X'. EXIT.    
        ENDIF.                          
      ENDLOOP.                          
    ENDIF.                              
    IF TAB_DIFFERENT = SPACE.           
    ENDIF.                              
    IF TAB1[] = TAB2[].  
    ENDIF.               
    Modify selected components
    LOOP AT TAB.           
    TAB-DATE = SY-DATUM. 
    MODIFY TAB.          
    ENDLOOP.               
    WA-DATE = SY-DATUM.                    
    LOOP AT TAB.                           
    MODIFY TAB FROM WA TRANSPORTING DATE.
    ENDLOOP.                               
    Appending two internal tables
    LOOP AT TAB_SRC.              
      APPEND TAB_SRC TO TAB_DEST. 
    ENDLOOP
    APPEND LINES OF TAB_SRC TO TAB_DEST.
    Deleting a set of lines
    LOOP AT TAB_DEST WHERE K = KVAL. 
      DELETE TAB_DEST.               
    ENDLOOP
    DELETE TAB_DEST WHERE K = KVAL.
    Tools available in SAP to pin-point a performance problem
          The runtime analysis (SE30)
          SQL Trace (ST05)
          Tips and Tricks tool
          The performance database
    Optimizing the load of the database
    Using table buffering
    Using buffered tables improves the performance considerably. Note that in some cases a stament can not be used with a buffered table, so when using these staments the buffer will be bypassed. These staments are:
    Select DISTINCT
    ORDER BY / GROUP BY / HAVING clause
    Any WHERE clasuse that contains a subquery or IS NULL expression
    JOIN s
    A SELECT... FOR UPDATE
    If you wnat to explicitly bypass the bufer, use the BYPASS BUFFER addition to the SELECT clause.
    Use the ABAP SORT Clause Instead of ORDER BY
    The ORDER BY clause is executed on the database server while the ABAP SORT statement is executed on the application server. The datbase server will usually be the bottleneck, so sometimes it is better to move thje sort from the datsbase server to the application server.
    If you are not sorting by the primary key ( E.g. using the ORDER BY PRIMARY key statement) but are sorting by another key, it could be better to use the ABAP SORT stament to sort the data in an internal table. Note however that for very large result sets it might not be a feasible solution and you would want to let the datbase server sort it.
    Avoid ther SELECT DISTINCT Statement
    As with the ORDER BY clause it could be better to avoid using SELECT DISTINCT, if some of the fields are not part of an index. Instead use ABAP SORT + DELETE ADJACENT DUPLICATES on an internal table, to delete duplciate rows.

  • Buffer table pool performance with return code 64 in ST05

    Hey guys,I had been meeting an issue causing poor Performance in my SAP system.For a full buffered table,I did trace it with ST12 and ST05,I found it's perfectly buffered in AS(as blue background entries in ST05 tracelist),but there were entries with high 'duration' and return code '64'(I know that's mean no records found),instead,the return code '0' entries worked fine,the duration  was pretty low.I had learned from documents of IBM/SAP(we're running with DB2 on AIX) that if you are just checking the exists of some records of certain table(access frequently),you may buffer them in AS,for now it seems to be going into opposite direction,that does  make sense with long time 'duration'.Detailed information seen the attachments.

    Hi Yunze,
    this performance issue can be resolved by adding 2 more steps in the code
    step 1 is required so that we will not loose any data else you can go ahead with yourcode by adding the field TZONE for both sort and delete adjacent duplicates and step 2.
    1. Pass the data from table IT_TZONE into a dummy table
        SORT dummy table using TZONE  and DELETE ADJACENT DUPLICATES from dummy table           using the field TZONE.
    2. Check the dummy table is initial or not before the select query on ZTMT102.
        If this is not empty then process the select query else skip the select query.
    you did not mention whether the field ZTRZONE is key field in the table ZTMY102 or not.
    if it is not a key field, if huge amount of data has to be fetched then create an index.
    the index will create a load on the database but it will improve the performance of the select query.
    Hope this will help you to resolve your issue and let me know in case of any questions.
    Regards,
    Phani

  • Index Organized Tables

    what is logical rowid in IOT?are they stored somwhere physically just like physical rowId's
    what are secondary indexes?
    what it means by leaf block splits?when and how it happens?
    and the primary key constraint for an index-organized table cannot be dropped, deferred, or disabled,,,,,Is it true,,,,,if Yes Then Y
    how does overflow works?how the two clauses are implemented PCTTHRESHOLD and INCLUDING.how they work?
    Edited by: Juhi on Oct 22, 2008 1:09 PM

    I'm sort-of tempted to just point you in the direction of the official documentation (the concepts guide would be a start. See http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/schema.htm#sthref759)
    But I would say one or two other things.
    First, physical rowids are not stored physically. I don't know why you'd think they were. The ROWID data type can certainly be used to store a rowid if you choose to do so, but if you do something like 'select rowid from scott.emp', for example, you'll see rowids that are generated on-the-fly. ROWID is a pseudo-column, not physically stored anywhere, but computed whenever needed.
    The difference between a physical rowid and a logical one used with IOTs comes down to a bit of relational database theory. It is a cast-iron rule of relational databases that a row, once inserted into a table, must never move. That is, the rowid it is assigned at the moment of its first insertion, must be the rowid it 'holds onto' for ever and ever. If you ever want to change the rowids assigned to rows in an ordinary table, you have to export them, truncate the table and then re-insert them: fresh insert, fresh rowid. (Oracle bends this rule for various maintenance and management purposes, whereby 'enable row movement' permits rows to move within a table, but the general case still applies mostly).
    That rule is obviously hopeless for index structures. Were it true, an index entry for 'Bob' who gets updated to 'Robert' would find itself next to entries for 'Adam' and 'Charlie', even though it now has an 'R' value. Effectively, a 'b' "row" in an index must be allowed to "move" to an 'r' sort of block if that's the sort of update that takes place. (In practice, an update to an index entry consists of performing a delete followed by a re-insert, but the physicalities don't change the principle: "rows" in an index must be allowed to move if their value changes; rows in a table don't move, whatever happens to their values)
    An IOT is, at the end of the day, simply an index with a lot more columns in it than a "normal" index would have -so it, too, has to allow its entires (its 'rows', if you like) to move. Therefore, an IOT cannot use a standard ROWID, which is assigned once and forever. Instead, it has to use something which takes account of the fact that its rows might wander. That is the logical rowid. It's no more "physical" than a physical rowid -neither are physically stored anywhere. But a 'physical' rowid is invariant; a logical one is not. The logical one is actually constructed in part from the primary key of the IOT -and that's the main reason why you cannot ever get rid of the primary key constraint on the IOT. Being allowed to do so would equate to allowing you to destroy the one organising principle for its contents that an IOT possesses.
    (See the section entitled "The ROWID Pseudocolumn" and following on this page: http://download.oracle.com/docs/cd/B28359_01/server.111/b28318/datatype.htm#CNCPT1845
    So IOTs have their data stored in them in primary key order. But they don't just contain the primary key, but every other column in the 'table definition' too. Therefore, just like with an ordinary table, you might want sometimes to search for data on columns which are NOT part of the primary key -and in that case, you might well want these non-primary key columns to be indexed. Therefore, you will create ordinary indexes on these columns -at this point, you're creating an index on an index, really, but that's a side issue, too! These extra indexes are called 'secondary indexes', simply because they are 'subsidiary indexes' to the main one, which is the "table" itself arranged in primary key order.
    Finally, a leaf block split is simply what happens when you have to make room for new data in an index block which is already packed to the rafters with existing data. Imagine an index block can only contain four entries, for example. You fill it with entries for Adam, Bob, Charlie, David. You now insert a new record for 'Brian'. If this was a table, you could throw Brian into any new block you like: data in a table has no positional significance. But entries in an index MUST have positional significance: you can't just throw Brian in amongst the middle of a lot of Roberts, Susans and Tanyas. Brian HAS to go in between the existing entires for Bob and Charlie. Yet you can't just put him in the middle of those two, because then you'd have five entries in a block, not four, which we imagined for the moment to be the maximum allowed. So what to do? What you do is: obtain a new, empty block. Move Charlie and David's entries into the new block. Now you have two blocks: Adam-Bob and Charlie-David. Each only has two entries, so each has two 'spaces' to accept new entries. Now you have room to add in the entry for Brian... and so you end up with Adam-Bob-Brian and Charlie-David.
    The process of moving some index entries out of one block into a new one so that there's room to allow new entries to be inserted in the middle of existing ones is called a block split. They happen for other reasons, too, so this is just a gloss treatment of them, but they give you the basic idea. It's because of block splits that indexes (and hence IOTs) see their "rows" move: Charlie and David started in one block and ended up in a completely different block because of a new (and completely unrelated to them) insert.
    Very finally, overflow is simply a way of splitting off data into a separate table segment that wouldn't sensibly be stored in the main IOT segment itself. Suppose you create an IOT containing four columns: one, a numeric sequence number; two, a varchar2(10); three, a varchar2(15); and four, a blob. Column 1 is the primary key.
    The first three columns are small and relatively compact. The fourth column is a blob data type -so it could be storing entire DVD movies, multi-gigabyte-sized monsters. Do you really want your index segment (for that is what an IOT really is) to balloon to huge sizes every time you add a new row? Probably not. You probably want columns 1 to 3 stored in the IOT, but column 4 can be bumped off over to some segment on its own (the overflow segment, in fact), and a link (actually, a physical rowid pointer) can link from the one to the other. Left to its own devices, an IOT will chop off every column after the primary key one when a record which threatens to consume more than 50% of a block gets inserted. However, to keep the main IOT small and compact and yet still contain non-primary key data, you can alter these default settings. INCLUDE, for example, allows you to specify which last non-primary key column should be the point at which a record is divided between 'keep in IOT' and 'move out to overflow segment'. You might say 'INCLUDE COL3' in the earlier example, so that COL1, COL2 and COL3 stay in the IOT and only COL4 overflows. And PCTTHRESHOLD can be set to, say, 5 or 10 so that you try to ensure an IOT block always contains 10 to 20 records -instead of the 2 you'd end up with if the default 50% kicked in.

  • Need suggestion on adding Index on table

    Hi,
    There is table called customer_locations in my database which has records about more then 5000 rows, When we write some select query to fetch data from this table takes too much time to load the data.
    Need a suggestion how to add index to increase the performance on this table. also which type of index to be added need a suggestion
    table sql script is mentioned below
    CREATE TABLE "CUSTOMER_LOCATIONS"
    (     "LOCATION_ID" NUMBER NOT NULL ENABLE,
         "COMPANY_NAME" VARCHAR2(512),
         "ADDRESS_LINE_1" VARCHAR2(512),
         "ADDRESS_LINE_2" VARCHAR2(512),
         "PHONE_NUMBER" VARCHAR2(255),
         "FAX_NUMBER" VARCHAR2(255),
         "CITY" VARCHAR2(512),
         "STATE" VARCHAR2(512),
         "ZIP" VARCHAR2(100),
         "COUNTRY" VARCHAR2(255),
         "CREATED_BY" VARCHAR2(512),
         "CREATED_DATE" TIMESTAMP (6),
         "MODIFIED_BY" VARCHAR2(512),
         "MODIFIED_DATE" TIMESTAMP (6),
         "DOMAIN_ID" NUMBER,
         "LOCATION_TYPE" VARCHAR2(255),
         "STATUS" VARCHAR2(50),
         "IB_STATUS" VARCHAR2(100),
         "OLD_LOCATION_ID" VARCHAR2(50),
         CONSTRAINT "SS_CUSTOMER_LOCATIONS_PK" PRIMARY KEY ("LOCATION_ID") ENABLE
    Please suggest
    Thanks
    Sudhir

    Hi Sudhir,
    Since you have no predicates it would be unavoidable to have FULL TABLE SCAN. But let me tell you that FULL TABLE SCANS are not bad.
    Just to help you with, the below code can enunciate the use of Indexes:
    drop table test_table;
    create table test_Table as select * from all_objects where rownum < 5001;
    select * from user_ind_columns where table_name = 'TEST_TABLE';
    --No rows fetched.
    explain plan for
    select object_name || ' is a ' || object_type as OBJ_DESC, object_id
      from test_table;
    --5000 Rows fetched
    select operation, options, object_name, object_alias, object_instance, object_type, optimizer, depth, position, cost, cardinality, cpu_cost, io_cost
    from plan_table;
    OPERATION               OPTIONS     OBJECT_NAME     OBJECT_ALIAS          OBJECT_INSTANCE     OBJECT_TYPE     OPTIMIZER     DEPTH     POSITION     COST     CARDINALITY     CPU_COST     IO_COST
    SELECT STATEMENT     (NULL)     (NULL)          (NULL)                    (NULL)               (NULL)          ALL_ROWS     0          19               19          5000          1698651          19     
    TABLE ACCESS          FULL     TEST_TABLE     TEST_TABLE@SEL$1     1                    TABLE          (NULL)          1          1               19          5000          1698651          19
    alter table test_Table add constraint pk_object_id PRIMARY KEY (object_id);
    explain plan for
    select object_name || ' is a ' || object_type as OBJ_DESC, object_id
      from test_table
    where object_id = 26;
    select operation, options, object_name, object_alias, object_instance, object_type, optimizer, depth, position, cost, cardinality, cpu_cost, io_cost
    from plan_table
    where statement_id = 'WITH_PK';
    OPERATION               OPTIONS               OBJECT_NAME          OBJECT_ALIAS          OBJECT_INSTANCE     OBJECT_TYPE          OPTIMIZER     DEPTH     POSITION     COST     CARDINALITY     CPU_COST     IO_COST
    SELECT STATEMENT     (NULL)               (NULL)               (NULL)                    (NULL)               (NULL)               ALL_ROWS     0          2               2          1               15543          2
    TABLE ACCESS          BY INDEX ROWID     TEST_TABLE          TEST_TABLE@SEL$1     1                    TABLE                              1          1               2          1               15543          2
    INDEX                    UNIQUE SCAN          PK_OBJECT_ID     TEST_TABLE@SEL$1     (NULL)               INDEX (UNIQUE)     ANALYZED     2          1               1          1               8171          1Let me know if it help or if you still have any concerns.
    Regards,
    P
    Edited by: PurveshK on May 29, 2012 12:40 PM

  • Heap tables and index organized tables

    I performing migration from mssql server to oracle 10gr2 rdbms, in mssql all tables have clustered pk, index. Is it necessary to use index organized tables for that migration, or enough ordinal heap organized tables and what differences between those tables, and mssql tables
    Thanx

    In Oracle, the typical table is a standard 'heap' table. Stuff goes into the heap table randomly, and randomly comes out.
    An Index Organizaed Tables is somewhat similar to a Cluster Index in SS. It can have some performance advantages over heap tables - when the heap table has an associated index on the primary key.
    The IOT can also have some disadvantages, such as the need for an Overflow table to handle the extra data when a row doesn't conveniently fit in a block (implying multiple I/Os), and an extra translation table if bitmap indexes are required (implying extra I/Os).
    An unintelligent developer will generally believe that Oracle and SQL Server are the same - after all they both run SQL - and will attempt to port by a simple translation of syntax.
    An intelligent developer will test both styles of tables, during a port. Such a developer will also be quick to learn about the changes in internals (such as locking mechanisms) and will realize that different styles of coding are required for many application situations.
    I recommend reading Tom Kyte's books to get handle on pros and cons as well as testing techniques to help a developer become intelligent.

  • Design table for performance (order - ordervisibility)

    I have tables like order, orderitem, etc. and requirements for order visibility:
    - One order can be seen by many users
    - One user can see many orders
    create table order (orderid number, ...);
    create table ordervisibility (orderid number, username varchar2(20));
    Order size is estimated to be >=500Mio. Application is a data warehouse with reporting.
    The relationship order - user will be skewed: some users will be allowed to see many orders while some will only see a small percentage.
    How should we design the system for performance?
    We think about creating table ordervisibility as index-organized table. Or are there better approaches like partitioning? Or is the approach with tables order na ordervisibility already suboptimal?

    <<<What is your 4 digit Oracle version (result of SELECT * FROM V$VERSION)?
    The system does not exist yet. Version will be derived from the requirements or most likely the latest version (e.g. 11.2.0.3 EE with partitioning option)
    <<<Are you wanting to prevent users from seeing other orders? You said one user can see many orders but are they NOT supposed to see other orders?
    Yes, you are right. We want to prevent other users to see orders that do not belong to them.
    <<<What determines which orders a user is allowed to see? A state code, a region code?
    The user in the OLTP system decides who can see orders (the user creating the order and maybe other users he selects)
    <<<Does this database, data and system already exist or is this a new design? Are there any other security mechanisms already in place? Is any of your data currently encrypted?
    The system does not exist yet. No other security mechanisms are planned (e.g. encryption).
    VPD is considered to implement the visibility (or alternatively views.)

  • Gathering statistics on interMedia indexes and tables

    Has anyone found any differences (like which one is better or worse) between using the ANALYZE sql command, dbms_utility package, or dbms_stats package to compute or estimate statistics for interMedia text indexes and tables for 8.1.6? I've read the documentation on the subject, but it is still unclear as to which method should be used. The interMedia text docs say the ANALYZE command should be used, and the dbms_stats docs say that dbms_stats should be used.
    Any help or past experience will be grateful.
    Thanks,
    jj

    According to the Support Document "Using statistics with Oracle Text" (Doc ID 139979.1), no:
    Q. Should we gather statistics on the underlying DR$/DR# tables? If yes/no, why?
    A. The recommendation is NO. All internal recursive queries have hints to fix the plans that are deemed most optimal. We have seen in the past that statistics on the underlying DR$ tables may cause query plan changes leading to serious query performance problems.
    Q. Should we gather statistics on Text domain indexes ( in our example above, BOOKS_INDEX)? Does it have any effect?
    A: As documented in the reference manual, gathering statistics on Text domain index will help CBO to estimate selectivity and costs for processing a CONTAINS() predicate. If the Text index does not have statistics collected, default selectivity and cost will be used.
    So 'No' on the DR$ tables and indexes, 'yes' on the user table being indexed.

  • SQLDeveloper 1.5.4 Table browsing performance issue

    Hi all,
    I had read of previous posts regarding SQLDeveloper 1.5.3 table browsing performance issues. I downloaded and installed version 1.5.4 and it appears the problem has gotten worse!
    It takes ages to display rows of this particular table (the structure is shown below). It takes much longer to view it in Single Record format. Then attempting to Export the data is another frustrating exercise. By the way, TOAD does not seem to have this problem so I guess it is a SQLDeveloper bug.
    Can someone help with any workarounds?
    Thanks
    Chiedu
    Here is the table structure:
    create table EMAIL_SETUP
    APPL_ID VARCHAR2(10) not null,
    EML_ID VARCHAR2(10) not null,
    EML_DESC VARCHAR2(80) not null,
    PRIORITY_NO_DM NUMBER(1) default 3 not null
    constraint CC_EMAIL_SETUP_4 check (
    PRIORITY_NO_DM in (1,2,3,4,5)),
    DTLS_YN VARCHAR2(1) default '0' not null
    constraint CC_EMAIL_SETUP_5 check (
    DTLS_YN in ('0','1')),
    ATT_YN VARCHAR2(1) default '0' not null
    constraint CC_EMAIL_SETUP_6 check (
    ATT_YN in ('0','1')),
    MSG_FMT VARCHAR2(5) default 'TEXT' not null
    constraint CC_EMAIL_SETUP_7 check (
    MSG_FMT in ('TEXT','HTML')),
    MSG_TMPLT VARCHAR2(4000) not null,
    MSG_MIME_TYPE VARCHAR2(500) not null,
    PARAM_NO NUMBER(2) default 0 not null
    constraint CC_EMAIL_SETUP_10 check (
    PARAM_NO between 0 and 99),
    IN_USE_YN VARCHAR2(1) not null
    constraint CC_EMAIL_SETUP_11 check (
    IN_USE_YN in ('0','1')),
    DFLT_USE_YN VARCHAR2(1) default '0' not null
    constraint CC_EMAIL_SETUP_12 check (
    DFLT_USE_YN in ('0','1')),
    TAB_NM VARCHAR2(30) null ,
    FROM_ADDR VARCHAR2(80) null ,
    RPLY_ADDR VARCHAR2(80) null ,
    MSG_SBJ VARCHAR2(100) null ,
    MSG_HDR VARCHAR2(2000) null ,
    MSG_FTR VARCHAR2(2000) null ,
    ATT_TYPE_DM VARCHAR2(4) null
    constraint CC_EMAIL_SETUP_19 check (
    ATT_TYPE_DM is null or (ATT_TYPE_DM in ('RAW','TEXT'))),
    ATT_INLINE_YN VARCHAR2(1) null
    constraint CC_EMAIL_SETUP_20 check (
    ATT_INLINE_YN is null or (ATT_INLINE_YN in ('0','1'))),
    ATT_MIME_TYPE VARCHAR2(500) null ,
    constraint PK_EMAIL_SETUP primary key (EML_ID)
    )

    Check Tools | Preferences | Database | Advanced Parameters and post the value you have there.
    Try setting it to a small number and report if you see any improvement.
    -Raghu

Maybe you are looking for

  • Fork and BPM

    Hi I am using Fork in the BPM to collect and merge 3 messages. This is same as STD pattern "BpmPatternCollectMultiIf". It is working fine, it collects--> transforms --> sends. But always two PE are in "In process" state with a "clock" indicator. I tr

  • Controlling the name of a PDF split

    I need to keep a consitant number of digits in the name of the PDF.  When I split a document, it increments.  How can I make the names be either 3 or 4 digits consistantly. Need: PDF_0001.pdf (page 1) PDF_0002.pdf (page 2) PDF_0003.pdf (page 3) PDF_0

  • Novice AccessControlException Problem

    I am trying to get my first servlet to work correctly from an applet on a different machine. Here are the facts. 1. The applet works correctly using localhost running on the same machine as Tomcat. 2. The servlet URL works correct when entered direct

  • HP printers stopped printing Black

    So, I keep software up to date.  I have 3 printers (don't ask why).  An HP Officejet 6500 E709n that is hardwired to the router (wifi was not good), an HP Officejet 6000 E609n this is connected by wifi but I don't use it much, and an HP LaserJet P205

  • Error updating User Table (ODBC - 2035)

    Hello all. Im having a problem when I try to update an user table @tbldoc and @tbldetail. "This entry already exist in the following tables 'table' (@tbldoc)" First time I have this issue was using my UI addon, my form is auto managed... then I try t