简体   繁体   English

提高SQL查询的性能

[英]Increase the performance of a SQL query

I have a tranctions table in which I need to get the transtions date and time for 5 differnect tractions (order drop, order pick, order Address labeled, loaded and ship). 我有一个tranctions表,我需要在其中获取5种不同牵引力的转换日期和时间(订单下降,订单选择,标有订单的地址,已装载并已发货)。

For each order I'm trying to get these transtions time for specific date and on orders we ship on those date. 对于每个订单,我都尝试获取特定日期以及我们在该日期发货的订单的这些转换时间。 My query run almost for every to get these information. 我的查询几乎每个人都运行以获取这些信息。

Is there a better way to rewrite this? 有没有更好的方法可以重写它? I would really appreciate your help. 我将衷心感谢您的帮助。

解释计划

Historymaster的索引

SELECT
    "ORDER",
     MAX(CASE WHEN "ACTION" = 'DNLD' THEN TO_CHAR(datetimecreated,'yyyy-mm-dd 
     hh24:mi')  END) AS ORDER_Drop_time,
     MAX(CASE WHEN "ACTION" = 'REQUEST' THEN TO_CHAR(datetimecreated,'yyyy-mm-dd hh24:mi')  END) AS Label_request_time,
     MAX(CASE WHEN "ACTION" = 'PICK' THEN TO_CHAR(datetimecreated,'yyyy-mm-dd hh24:mi')  END) AS pick_time,
     MAX(CASE WHEN "ACTION" = 'LOAD' THEN TO_CHAR(datetimecreated,'yyyy-mm-dd hh24:mi')  END) AS Load_TIME,
     MAX(CASE WHEN "ACTION" = 'SHIP' THEN TO_CHAR(datetimecreated,'yyyy-mm-dd hh24:mi')  END) AS SHIP_COM_TIME
FROM
    historymaster hm
WHERE
    "ORDER" IN (
        SELECT
            "ORDER"
        FROM
            historymaster
        WHERE
            datetimecreated >=:usestartdate
            AND   datetimecreated <=:useenddate
            AND   "ACTION" = 'SHIP'
            AND   "OBJECT" = 'OBORDLINE'
    ) -- Looking up order ID for ship transations and using it 
    AND   (
        (-- Order drop 
            "ACTION" = 'DNLD'
            AND   "OBJECT" = 'OBORDLINE'
            AND   actionmodifier IS NULL
            AND   reasoncode = '00'
        )
        OR --Address label request
         (
            "ACTION" = 'REQUEST'
            AND   "OBJECT" = 'LABEL'
            AND   "CLASS" = 'ADDR'
        )
        OR -- pick 
         (
            "ACTION" = 'PICK'
            AND   "OBJECT" = 'OBO'
            AND   "CLASS" = 'INVE'
            AND   actualquantity != 0
            AND   substr(ordertype,1,1) = 'N'
        )
        OR   -- Trailer Load
         (
            "ACTION" = 'LOAD'
            AND   "OBJECT" = 'OBO'
            AND   "CLASS" = 'INVE'
        )
        OR --Ship Complete 
         (
            "OBJECT" = 'OBORDLINE'
            AND   hm.package = ' '
            AND   actionmodifier IS NULL
            AND   "ACTION" = 'SHIP'
        )
    )
GROUP BY
    "ORDER";

Output: 输出:

ORDER         ORDER_Drop_time   Label_request_time  PICK_TIME   Load_TIME   SHIP_COM_TIME
D2KJJKJLB-35689 8/2/2018 9:50   8/6/2018 9:50   8/6/2018 8:50   8/6/2018 10:50  8/7/2018 14:16

You should use indexes if this query is getting slow. 如果查询变慢,则应使用索引。

The most important index I can think of is: 我能想到的最重要的索引是:

create index ix1 on historymaster ("OBJECT", "ACTION", datetimecreated);

Additionally, if you really want this query to be even faster, you can add: 此外,如果您确实希望此查询更快,可以添加:

create index ix2 on historymaster ("OBJECT", "ACTION", reasoncode);
create index ix3 on historymaster ("OBJECT", "ACTION", "CLASS");

Be careful not to add to many indexes to our tables, since it can make your INSERT s, UPDATE s, and DELETE s slow. 注意不要在表中添加很多索引,因为它会使您的INSERTUPDATEDELETE变慢。 There's a balance you need to find. 您需要找到一个平衡点。

Please retrieve the execution plan for the query. 请检索查询的执行计划。 To do it: 去做吧:

  1. Prepare the retrieval: 准备检索:

     drop table plan_table; 
  2. Create the execution plan: 创建执行计划:

     explain plan for select ... 
  3. Retrieve the execution plan: 检索执行计划:

     select plan_table_output from table(dbms_xplan.display('plan_table',null,'typical')); 

    Once you get it, add the plan to your question. 一旦获得,将计划添加到您的问题中。

Your query performs basically two access, so (provided you select only a small number of orders) you need two indexes to reflect it. 您的查询基本上执行两次访问,因此(假设您仅选择少量订单)需要两个索引来反映它。

The first index select the orders with propper action and object in a given time range 第一个索引选择给定时间范围内具有适当actionobjectorders

 ("ACTION","OBJECT",datetimecreated)

The second index then queries all records for those orders with requested action and object 然后,第二个索引查询所有记录以查找具有请求的actionobject那些orders

 ("ORDER", "ACTION" ,"OBJECT")

To demostrate the principal, I created a test table with 2M rows and 100K orders (see script below). 为了演示本金,我创建了一个包含2M行和10万个订单的测试表(请参见下面的脚本)。

Note, that I don't use reserved names (eg "ORDER" is order_id) and I use "neutral" names for action and object. 请注意,我不使用保留名称(例如,“ ORDER”为order_id),而对操作和对象使用“中性”名称。

select order_id,
max(case when action_id = 'A1' then datetimecreated end) as A1_date,
max(case when action_id = 'A2' then datetimecreated end) as A2_date,
max(case when action_id = 'A3' then datetimecreated end) as A3_date,
max(case when action_id = 'A4' then datetimecreated end) as A4_date,
max(case when action_id = 'A5' then datetimecreated end) as A5_date 
from test
where order_id in (
   select order_id
   from test
   where datetimecreated >= DATE'2018-02-05' and  datetimecreated <= DATE'2018-02-06' and
   action_id = 'A1' and object_id = 'O1')
AND
(action_id = 'A1' and object_id = 'O1' or
 action_id = 'A2' and object_id = 'O2' or
 action_id = 'A3' and object_id = 'O3' or
 action_id = 'A4' and object_id = 'O4' or
 action_id = 'A5' and object_id = 'O1')
group by order_id;


  ORDER_ID A1_DATE  A2_DATE  A3_DATE  A4_DATE  A5_DATE
---------- -------- -------- -------- -------- --------
       826 05.02.18 10.02.18 15.02.18 20.02.18 21.02.18
       833 05.02.18 10.02.18 15.02.18 20.02.18 21.02.18
.....
       823 05.02.18 10.02.18 15.02.18 20.02.18 21.02.18
       838 05.02.18 10.02.18 15.02.18 20.02.18 21.02.18

25 rows selected.

Elapsed: 00:00:00.10

You expect this execution plan - the inner NESTED LOOP performs the two access described above - see the access condition 5 and 7. 您期望此执行计划-内部NESTED LOOP执行上述两个访问-请参阅访问条件5和7。

Plan hash value: 1930696803

--------------------------------------------------------------------------------------------
| Id  | Operation                      | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |           |   223 | 13380 |    12   (9)| 00:00:01 |
|   1 |  HASH GROUP BY                 |           |   223 | 13380 |    12   (9)| 00:00:01 |
|   2 |   NESTED LOOPS                 |           |       |       |            |          |
|   3 |    NESTED LOOPS                |           |   223 | 13380 |    11   (0)| 00:00:01 |
|   4 |     TABLE ACCESS BY INDEX ROWID| TEST      |     1 |    30 |     4   (0)| 00:00:01 |
|*  5 |      INDEX RANGE SCAN          | TEST_IDX1 |     1 |       |     3   (0)| 00:00:01 |
|   6 |     INLIST ITERATOR            |           |       |       |            |          |
|*  7 |      INDEX RANGE SCAN          | TEST_IDX2 |     1 |       |     6   (0)| 00:00:01 |
|   8 |    TABLE ACCESS BY INDEX ROWID | TEST      |   502 | 15060 |     7   (0)| 00:00:01 |
--------------------------------------------------------------------------------------------

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

   5 - access("ACTION_ID"='A1' AND "OBJECT_ID"='O1' AND 
              "DATETIMECREATED">=TO_DATE(' 2018-02-05 00:00:00', 'syyyy-mm-dd hh24:mi:ss') AND 
              "DATETIMECREATED"<=TO_DATE(' 2018-02-06 00:00:00', 'syyyy-mm-dd hh24:mi:ss'))
   7 - access("ORDER_ID"="ORDER_ID" AND ("ACTION_ID"='A1' AND "OBJECT_ID"='O1' OR 
              "ACTION_ID"='A2' AND "OBJECT_ID"='O2' OR "ACTION_ID"='A3' AND "OBJECT_ID"='O3' OR 
              "ACTION_ID"='A4' AND "OBJECT_ID"='O4' OR "ACTION_ID"='A5' AND "OBJECT_ID"='O1'))

Here the script to produce test data to play with: 这里是产生测试数据的脚本:

create table test as 
with ord as (
select rownum order_id, date'2018-01-01' + rownum / 24 datetimecreated from dual connect by level <= 100000),
act as (
select 'A1' action_id, 'O1' object_id, 1 offset from dual union all
select 'A1' action_id, 'O2' object_id, 2 offset from dual union all
select 'A1' action_id, 'O3' object_id, 3 offset from dual union all
select 'A1' action_id, 'O4' object_id, 4 offset from dual union all
select 'A2' action_id, 'O1' object_id, 5 offset from dual union all
select 'A2' action_id, 'O2' object_id, 6 offset from dual union all
select 'A2' action_id, 'O3' object_id, 7 offset from dual union all
select 'A2' action_id, 'O4' object_id, 8 offset from dual union all
select 'A3' action_id, 'O1' object_id, 9 offset from dual union all
select 'A3' action_id, 'O2' object_id, 10 offset from dual union all
select 'A3' action_id, 'O3' object_id, 11 offset from dual union all
select 'A3' action_id, 'O4' object_id, 12 offset from dual union all
select 'A4' action_id, 'O1' object_id, 13 offset from dual union all
select 'A4' action_id, 'O2' object_id, 14 offset from dual union all
select 'A4' action_id, 'O3' object_id, 15 offset from dual union all
select 'A4' action_id, 'O4' object_id, 16 offset from dual union all
select 'A5' action_id, 'O1' object_id, 17 offset from dual union all
select 'A5' action_id, 'O2' object_id, 18 offset from dual union all
select 'A5' action_id, 'O3' object_id, 19 offset from dual union all
select 'A5' action_id, 'O4' object_id, 20 offset from dual)
select order_id, datetimecreated + offset datetimecreated, action_id,object_id  from ord
cross join act;

create index test_idx1 on test(action_id, object_id,datetimecreated);
create index test_idx2 on test(order_id,action_id, object_id);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM