3

我得到的响应时间约为 200 毫秒。我想进一步优化它。我怎样才能做到这一点?

CREATE OR REPLACE
PROCEDURE GETSTORES
(
LISTOFOFFERIDS IN VARCHAR2,
REF_OFFERS OUT TYPES.OFFER_RECORD_CURSOR
)
AS
BEGIN
  OPEN REF_OFFERS FOR
  SELECT
  /*+ PARALLEL(STORES 5) PARALLEL(MERCHANTOFFERS 5)*/
  MOFF.OFFERID,
  s.STOREID,
  S.LAT,
  s.LNG
  FROM
  MERCHANTOFFERS MOFF
  INNER JOIN STORES s ON MOFF.STOREID =S.STOREID
  WHERE
  MOFF.OFFERID IN
  (
    SELECT
      REGEXP_SUBSTR(LISTOFOFFERIDS,'[^,]+', 1, LEVEL)
    FROM
      DUAL CONNECT BY REGEXP_SUBSTR(LISTOFOFFERIDS, '[^,]+', 1, LEVEL) IS NOT NULL
  )
  ;
END
GETSTORES;

我正在使用 regex_substr 从 LISTOFOFFERIDS 中的逗号分隔字符串中获取 OfferID 列表。我已经在 Stores 表的 STOREID 上创建了索引,但无济于事。如果速度更快,实现相同目标的新方法也很好。

相同的类型声明:

create or replace

    PACKAGE TYPES
    AS
    TYPE OFFER_RECORD
    IS
      RECORD(
      OFFER_ID MERCHANTOFFERS.OFFERID%TYPE,
      STORE_ID STORES.STOREID%TYPE,
      LAT STORES.LAT%TYPE,
      LNG STORES.LNG%TYPE
      );
    TYPE OFFER_RECORD_CURSOR
    IS
      REF
      CURSOR
        RETURN OFFER_RECORD;
      END
      TYPES;

选择计划显示以下信息:

Plan hash value: 1501040938

-------------------------------------------------------------------------------------------------------------
| Id  | Operation                                  | Name           | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                           |                |   276 | 67620 |    17  (12)| 00:00:01 |
|*  1 |  HASH JOIN                                 |                |   276 | 67620 |    17  (12)| 00:00:01 |
|   2 |   NESTED LOOPS                             |                |       |       |            |          |
|   3 |    NESTED LOOPS                            |                |   276 | 61272 |     3  (34)| 00:00:01 |
|   4 |     VIEW                                   | VW_NSO_1       |     1 |   202 |     3  (34)| 00:00:01 |
|   5 |      HASH UNIQUE                           |                |     1 |       |     3  (34)| 00:00:01 |
|*  6 |       CONNECT BY WITHOUT FILTERING (UNIQUE)|                |       |       |            |          |
|   7 |        FAST DUAL                           |                |     1 |       |     2   (0)| 00:00:01 |
|*  8 |     INDEX RANGE SCAN                       | OFFERID_INDEX  |   276 |       |     0   (0)| 00:00:01 |
|   9 |    TABLE ACCESS BY INDEX ROWID             | MERCHANTOFFERS |   276 |  5520 |     0   (0)| 00:00:01 |
|  10 |   TABLE ACCESS FULL                        | STORES         |  9947 |   223K|    13   (0)| 00:00:01 |
-------------------------------------------------------------------------------------------------------------

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

   1 - access("MERCHANTOFFERS"."STOREID"="STORES"."STOREID")
   6 - filter( REGEXP_SUBSTR ('M1-Off2,M2-Off5,M2-Off9,M5-Off4,M10-Off1,M1-Off3,M2-Off4,M3-Off2,M4-Of
              f6,M5-Off1,M6-Off1,M8-Off1,M7-Off3,M1-Off1,M2-Off1,M3-Off1,M3-Off4,M3-Off5,M3-Off6,M4-Off1,M4-Off7,M2
              -Off2,M3-Off3,M5-Off2,M7-Off1,M7-Off2,M1-Off7,M2-Off3,M3-Off7,M5-Off5,M4-Off2,M4-Off3,M4-Off5,M8-Off2
              ,M6-Off2,M1-Off5,M1-Off6,M1-Off9,M1-Off8,M2-Off6,M2-Off7,M4-Off4,M9-Off1,M6-Off4,M1-Off4,M1-Off10,M2-
              Off8,M3-Off8,M6-Off3,M5-Off3','[^,]+',1,LEVEL) IS NOT NULL)
   8 - access("MERCHANTOFFERS"."OFFERID"="$kkqu_col_1")
4

3 回答 3

1
  1. 如果您的服务器支持它(似乎您想要它),请将提示更改为/*+ PARALLEL(S 8) PARALLEL(MOFF 8)*/. 当您有别名时,您必须在提示中使用别名。
  2. 您应该尝试 APC( STORES(STOREID, LAT, LNG))建议的复合索引
  3. 请回答问题:对于所提供的示例,您获得了多少不同的商店 ( select count(distinct storeid) from (your_query)) 以及 STORES 表中有多少家商店?( Select count(*) from Stores)?
  4. 你用 分析过表格dbms_stats.gather_table_stats吗?
  5. 我相信connect by查询不是问题。它在 0.02 秒内运行。
于 2012-09-27T06:18:46.640 回答
0

如果你看你解释计划,每个步骤的时间是相同的:没有明显的候选人可以专注于调整。

您发布的示例有 50 个 OFFERID 令牌。那是代表吗?他们映射到 276 家商店——这是一个代表性的比例吗?是否有任何优惠针对多个商店?

276 行约占行数的 2.7%,这是一个很小的 ​​sliver:但是,由于 STORES 似乎是一个非常紧凑的表,因此索引读取是否比全表扫描快是微不足道的。

要从数据库中榨取更多汁液,唯一显而易见的事情就是在 STORES(STOREID, LAT, LNG) 上建立一个复合索引;大概它不是一个看到很多 DML 的表,因此额外索引的开销不会太多。

最后一点:您的查询在 0.2 秒内执行。那么你希望它快多少呢?

于 2012-09-25T15:29:56.230 回答
0

考虑在连接中删除正则表达式,以便连接可以快速发生。
如果连接列上有索引,则连接可能会从嵌套循环移动到某种散列连接。

一旦你有了那个结果集(希望行更少),然后用你的正则表达式过滤它。

您可能会发现 WITH 语句在这个场景中很有帮助。

事情就这样。(未经测试的例子)

WITH
base AS
(
    SELECT /*+ PARALLEL(STORES 5) PARALLEL(MERCHANTOFFERS 5) */
           moff.OFFERID,
              s.STOREID,
              s.LAT,
              s.LNG
    FROM MERCHANTOFFERS moff
    INNER JOIN STORES s 
    ON MOFF.STOREID = S.STOREID
),
offers AS
(
    SELECT REGEXP_SUBSTR(LISTOFOFFERIDS,'[^,]+', 1, LEVEL) offerid
    FROM DUAL 
    CONNECT BY REGEXP_SUBSTR(LISTOFOFFERIDS, '[^,]+', 1, LEVEL) IS NOT NULL
)
SELECT base.*
FROM base,
     offers
WHERE base.offerid = offers.offerid

Oracle 可以将这两个视图执行到内存表中,然后连接。

没有担保人。您的里程可能会有所不同。你在寻找想法。这是一个想法。祝你好运。

如果我正确地记得提示章节,当您为表名命名时,您需要在提示中使用该别名。/*+ PARALLEL(s 5) PARALLEL(moff 5) */

我很好奇您为什么决定将值 5 作为提示。我的印象是甲骨文会根据系统负载和其他神秘情况为其选择最佳价值。

于 2012-09-26T16:07:56.903 回答