如何优化接下来的oracle查询?

发布于 2024-12-22 14:47:01 字数 1095 浏览 2 评论 0原文

我有2张桌子。表“Accs”包含 900 万行(3 列:acc_id、月份、年份)。 首先我需要提取包含部分帐号条目的记录, 然后在这些记录中查找完整匹配,如果没有——则先查找部分匹配,

WITH t AS (
  SELECT a.acc_id,
         t1.as,
         t1.cust,
         t1.curr,
         t1.code,
         t1.depart,
         t1.sdate,
         t1.stype,
         t1.amount,
         t1.s_id
  FROM table1 t1 
  LEFT JOIN Accs a 
  ON SUBSTR(a.acc_id,7,12)=t1.curr||LPAD(t1.code,4,'0')||LPAD(t1.depart,3,'0')
  WHERE t1.sdate='20.11.2011' AND t1.stype='A' AND a.month=11 ANd a.year=2011)
SELECT MAX(t.s_id),
       (CASE WHEN t.as='000000' 
             THEN (CASE WHEN ac2.acc_id IS NOT NULL THEN ac2.acc_id ELSE t.acc_id END) 
             ELSE t.cust||t.curr||LPAD(t.code,4,'0')||LPAD(t.depart,3,'0') END) acc_id
FROM t 
LEFT JOIN (SELECT t.acc_id FROM t) ac2 
ON SUBSTR(ac2.acc_id,1,6)='000'||LPAD(t.depart,3,'0')
GROUP BY      
       (CASE WHEN t.as='000000' 
             THEN (CASE WHEN ac2.acc_id IS NOT NULL THEN ac2.acc_id ELSE t.acc_id END) 
             ELSE t.cust||t.curr||LPAD(t.code,4,'0')||LPAD(t.depart,3,'0') END)

这样查询需要很长时间。我这样做是否正确?

I have 2 tables. Table "Accs" contains 9 million rows (3 columns: acc_id, month, year).
First I need to extract the records that contain the partial entry of account number,
and then in these records to find the complete match, if not - then the first partial match

WITH t AS (
  SELECT a.acc_id,
         t1.as,
         t1.cust,
         t1.curr,
         t1.code,
         t1.depart,
         t1.sdate,
         t1.stype,
         t1.amount,
         t1.s_id
  FROM table1 t1 
  LEFT JOIN Accs a 
  ON SUBSTR(a.acc_id,7,12)=t1.curr||LPAD(t1.code,4,'0')||LPAD(t1.depart,3,'0')
  WHERE t1.sdate='20.11.2011' AND t1.stype='A' AND a.month=11 ANd a.year=2011)
SELECT MAX(t.s_id),
       (CASE WHEN t.as='000000' 
             THEN (CASE WHEN ac2.acc_id IS NOT NULL THEN ac2.acc_id ELSE t.acc_id END) 
             ELSE t.cust||t.curr||LPAD(t.code,4,'0')||LPAD(t.depart,3,'0') END) acc_id
FROM t 
LEFT JOIN (SELECT t.acc_id FROM t) ac2 
ON SUBSTR(ac2.acc_id,1,6)='000'||LPAD(t.depart,3,'0')
GROUP BY      
       (CASE WHEN t.as='000000' 
             THEN (CASE WHEN ac2.acc_id IS NOT NULL THEN ac2.acc_id ELSE t.acc_id END) 
             ELSE t.cust||t.curr||LPAD(t.code,4,'0')||LPAD(t.depart,3,'0') END)

This query takes a long time. Whether correctly I do?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

尤怨 2024-12-29 14:47:01

第一次尝试

如果没有实际的表结构和数据,无法真正测试它,但我做了一些小的更改,有时确实会产生很大的影响。

首先,我将with部分中的LEFT JOIN更改为INNER JOIN。由于您在 WHERE 子句中使用 a 的值,因此它无论如何都会起到 inner join 的作用,并且通常要快得多,尤其是有了这么多的数据和适当的索引。

我将内部 CASE 更改为 NVL,因为这本质上就是它的作用。不知道这样会不会加快速度。

将字符串连接从外部查询移至 with 部分。

这些只是一些微小的变化,可能会产生从没有影响到相当大的影响。至少您可以在更改表结构本身之前尝试这些,尽管无论如何这样做可能是个好主意。

WITH t AS 
(
  SELECT 
    a.acc_id,
    t1.as,
    t1.cust,
    t1.curr,
    t1.code,
    t1.depart,
    t1.sdate,
    t1.stype,
    t1.amount,
    t1.s_id,
    t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') as groupfield
  FROM 
    table1 t1 
    INNER JOIN Accs a
      ON SUBSTR(a.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
  WHERE 
    t1.sdate = '20.11.2011' AND t1.stype = 'A' AND a.month = 11 ANd a.year = 2011
)
SELECT
  MAX(t.s_id),
  (CASE WHEN t.as = '000000' THEN 
    NVL(ac2.acc_id, t.acc_id)
  ELSE
    t.groupfield
  END) acc_id
FROM 
  t 
  LEFT JOIN t ac2 on ac2 
    ON SUBSTR(ac2.acc_id, 1, 6) = '000' || LPAD(t.depart, 3, '0')
GROUP BY      
  (CASE WHEN t.as = '000000' THEN 
    NVL(ac2.acc_id, t.acc_id)
  ELSE
    t.groupfield
  END)

第二次尝试

在对您的查询进行了更多研究之后,我想知道您是否不能将其设为单个/简单查询,而不是使用with。我认为通过首先内部加入 Accs,然后在附加条件下再次加入 Accs,您确实是一个很好的方法。

  SELECT 
    MAX(t1.s_id) AS s_id,
    CASE WHEN t.as = '000000' THEN
      NVL(a2.acc_id, a.acc_id)
    ELSE
      t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
    END AS acc_id
  FROM 
    table1 t1 
    INNER JOIN Accs a
      ON SUBSTR(a.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
      AND a.month = 11 AND a.year = 2011
    LEFT JOIN Accs a2
      ON SUBSTR(a2.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
      AND a2.month = 11 AND a2.year = 2011
      AND SUBSTR(a2.acc_id, 1, 6) = '000' || LPAD(t1.depart, 3, '0')
  WHERE 
    t1.sdate = '20.11.2011' AND t1.stype = 'A'
  GROUP BY 
    CASE WHEN t.as = '000000' THEN
      NVL(a2.acc_id, a.acc_id)
    ELSE
      t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') as groupfield
    END AS acc_id

First attempt

Can't really test it without having your actual table structure and data, but I've made a few minor changes that do sometimes have big impact.

First of all, I changed the LEFT JOIN in the with part to an INNER JOIN. Since you use values of a in the WHERE clause, it would function as an inner join anyway, and it is usually a lot faster, especially with this amount of data and proper indexes.

I changed the inner CASE to NVL, because that's essentially what it does. Don't know if that would speed things up.

Moved the string concatenation from the outer query to the with part.

These are just small changes that may have anywhere from no to quite some effect. At least you can try these before altering the table structure itself, although it may be a good idea to do that anyway.

WITH t AS 
(
  SELECT 
    a.acc_id,
    t1.as,
    t1.cust,
    t1.curr,
    t1.code,
    t1.depart,
    t1.sdate,
    t1.stype,
    t1.amount,
    t1.s_id,
    t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') as groupfield
  FROM 
    table1 t1 
    INNER JOIN Accs a
      ON SUBSTR(a.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
  WHERE 
    t1.sdate = '20.11.2011' AND t1.stype = 'A' AND a.month = 11 ANd a.year = 2011
)
SELECT
  MAX(t.s_id),
  (CASE WHEN t.as = '000000' THEN 
    NVL(ac2.acc_id, t.acc_id)
  ELSE
    t.groupfield
  END) acc_id
FROM 
  t 
  LEFT JOIN t ac2 on ac2 
    ON SUBSTR(ac2.acc_id, 1, 6) = '000' || LPAD(t.depart, 3, '0')
GROUP BY      
  (CASE WHEN t.as = '000000' THEN 
    NVL(ac2.acc_id, t.acc_id)
  ELSE
    t.groupfield
  END)

Second attempt

After looking a little more into your query, I wonder if you cannot just make it a single/simple query instead of using with. I think by first inner joining Accs and then left joining Accs again with the extra condition, you're a good way to go really.

  SELECT 
    MAX(t1.s_id) AS s_id,
    CASE WHEN t.as = '000000' THEN
      NVL(a2.acc_id, a.acc_id)
    ELSE
      t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
    END AS acc_id
  FROM 
    table1 t1 
    INNER JOIN Accs a
      ON SUBSTR(a.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
      AND a.month = 11 AND a.year = 2011
    LEFT JOIN Accs a2
      ON SUBSTR(a2.acc_id, 7, 12) = t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0')
      AND a2.month = 11 AND a2.year = 2011
      AND SUBSTR(a2.acc_id, 1, 6) = '000' || LPAD(t1.depart, 3, '0')
  WHERE 
    t1.sdate = '20.11.2011' AND t1.stype = 'A'
  GROUP BY 
    CASE WHEN t.as = '000000' THEN
      NVL(a2.acc_id, a.acc_id)
    ELSE
      t1.cust || t1.curr || LPAD(t1.code, 4, '0') || LPAD(t1.depart, 3, '0') as groupfield
    END AS acc_id
秋日私语 2024-12-29 14:47:01

您可以尝试创建基于函数的索引,如下所示:

create index xxx on accs (SUBSTR(a.acc_id,7,12));

You could try creating function-based indexes like this one:

create index xxx on accs (SUBSTR(a.acc_id,7,12));
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文