简体   繁体   English

提高Oracle和Postgres中的查询性能

[英]Improve Query performance in Oracle & Postgres

I need to do multiple joins like below query.Have around 200 CAT_CODE. 我需要像下面的查询一样进行多个联接。大约有200个CAT_CODE。

Primary Table(PRIM): 主表(PRIM):

NUM     CAT1_CODE   CAT2_CODE   CAT3_CODE
A          1           y           q     
B          2           e           a     
C          3           s           z  

Secondary Table(LOV): 辅助表(LOV):

CATEGORY    COLUMN_LKP        EXT_CODE
CAT1_CODE       1                AB
CAT1_CODE       2                CD
CAT1_CODE       3                HI
CAT2_CODE       y                JL
CAT2_CODE       e                QD
CAT2_CODE       s                AH
CAT3_CODE       q                CD
CAT3_CODE       a                MS
CAT3_CODE       z                EJ

REQUIRED OUTPUT: 所需的输出:

NUM CAT1    CAT2    CAT3
A    AB      JL      CD
B    CD      QD      MS
C    HI      AH      EJ

SQL: SQL:

I have written a simple query to accomplish this task. 我已经编写了一个简单的查询来完成此任务。 Do you think, this would be right approach? 您认为这是正确的方法吗? Any other ways, to improve this query? 还有其他方法可以改善此查询吗? Right now, I'm using both Oracle and Postgres. 现在,我同时使用Oracle和Postgres。

SELECT 
NUM,
(SELECT EXT_CODE FROM TEST_LOV 
WHERE CATEGRY='CAT1_CODE' AND COLUMN_LKP=A.CAT1_CODE) CAT1,
(SELECT EXT_CODE FROM TEST_LOV 
WHERE CATEGRY='CAT2_CODE' AND COLUMN_LKP=A.CAT2_CODE) CAT2,
(SELECT EXT_CODE FROM TEST_LOV 
WHERE CATEGRY='CAT3_CODE' AND COLUMN_LKP=A.CAT3_CODE) CAT3 
FROM 
TEST_PRIM A

TEST_LOV is scanned multiple times. TEST_LOV被扫描了多次。

Query Plan: 查询计划:

-------------------------------------------------------------------------------
| Id  | Operation         | Name      | Rows  | Bytes | Cost (%CPU)| Time     |
-------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |     3 |    24 |    17   (0)| 00:00:01 |
|*  1 |  TABLE ACCESS FULL| TEST_LOV  |     1 |    15 |     3   (0)| 00:00:01 |
|*  2 |  TABLE ACCESS FULL| TEST_LOV  |     1 |    15 |     3   (0)| 00:00:01 |
|*  3 |  TABLE ACCESS FULL| TEST_LOV  |     1 |    15 |     3   (0)| 00:00:01 |
|   4 |  TABLE ACCESS FULL| TEST_PRIM |     3 |    24 |     3   (0)| 00:00:01 |
-------------------------------------------------------------------------------

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

   1 - filter("CATEGRY"='CAT1_CODE' AND "COLUMN_LKP"=:B1)
   2 - filter("CATEGRY"='CAT2_CODE' AND "COLUMN_LKP"=:B1)
   3 - filter("CATEGRY"='CAT3_CODE' AND "COLUMN_LKP"=:B1)

In oracle, you can unpivot the prim table and use the result to join to lov table. 在oracle中,可以unpivot透视表,然后使用结果联接到lov表。

with primunpiv as 
(select * from test_prim
 unpivot
 (code for category in (CAT1_CODE,CAT2_CODE,CAT3_CODE))
)
select p.num
,max(case when p.category = 'CAT1_CODE' then l.ext_code end) cat1
,max(case when p.category = 'CAT2_CODE' then l.ext_code end) cat2
,max(case when p.category = 'CAT3_CODE' then l.ext_code end) cat3
from primunpiv p
join testlov l on p.code = l.column_lkp and p.category = l.category
group by p.num

You should never embed sql queries in the select component of your statement if at all possible. 绝对不要将sql查询嵌入到语句的select组件中。

You could rewrite it so that it goes against all the tables appropriately. 您可以重写它,使其与所有表正确对应。

select num, ... from test_prim a , test_lov b , test_lov c , test_lov d where a.cat1_code = b.column_lkup and b.catgry = 'CAT1_CODE' and ... 选择num,...从test_prim a,test_lov b,test_lov c,test_lov d其中a.cat1_code = b.column_lkup和b.catgry ='CAT1_CODE'并...

The only problem with this approach is in the case that one of the categories in test_prim is null, in which case your joins against test_lov have to be outer joins. 这种方法的唯一问题是在test_prim中的类别之一为null的情况下,在这种情况下,您对test_lov的联接必须是外部联接。

This also has the benefit of using indexes if the test_lov.column_lkup column has an index on it. 如果test_lov.column_lkup列上有索引,则这也具有使用索引的好处。

LOL - this is turning into a run-on. 大声笑-这变成了磨合。 Your selects in the select clause basically cause full table scans and then the resolution occurs in the PGA, which is slow. 您在select子句中进行的选择基本上会引起全表扫描,然后在PGA中进行解析,这很慢。 The other approach stops each time there is a success, so it's much faster. 另一种方法是每次成功都会停止,因此速度更快。

My oracle isn't very good, but I've done a similar thing in the past in SQL Server. 我的甲骨文不是很好,但是过去我在SQL Server中做过类似的事情。 I think this should work, and might improve your performance. 我认为这应该可行,并且可以改善您的效果。 If there's always a corresponding record for each different CAT code, you can change these to INNER JOIN's. 如果每个不同的CAT代码始终有对应的记录,则可以将其更改为INNER JOIN。

SELECT 
NUM,
B.EXT_CODE CAT1, 
C.EXT_CODE CAT2, 
D.EXT_CODE CAT3
FROM TEST_PRIM A
LEFT JOIN TEST_LOV B ON B.CATEGRY='CAT1_CODE' AND B.COLUMN_LKP = A.CAT1_CODE
LEFT JOIN TEST_LOV C ON C.CATEGRY='CAT2_CODE' AND C.COLUMN_LKP = A.CAT2_CODE
LEFT JOIN TEST_LOV D ON D.CATEGRY='CAT3_CODE' AND C.COLUMN_LKP = A.CAT3_CODE

SQLFiddle: Postgres SQLFiddle:Postgres

WITH
cat1 AS ( SELECT EXT_CODE, COLUMN_LKP FROM LOV WHERE CATEGORY='CAT1_CODE' ),
cat2 AS ( SELECT EXT_CODE, COLUMN_LKP FROM LOV WHERE CATEGORY='CAT2_CODE' ),
cat3 AS ( SELECT EXT_CODE, COLUMN_LKP FROM LOV WHERE CATEGORY='CAT3_CODE' )

SELECT num, cat1.ext_code CAT1, cat2.ext_code CAT2, cat3.ext_code CAT3
FROM prim
LEFT JOIN cat1 ON prim.cat1_code::varchar(1) = cat1.column_lkp
LEFT JOIN cat2 ON prim.cat2_code = cat2.column_lkp
LEFT JOIN cat3 ON prim.cat3_code = cat3.column_lkp
;

Problems w/ Your Question 有您的问题的问题

  1. Your query uses TEST_LOV and TEST_PRIM , but your question labels them as LOV and PRIM , respectively 您的查询使用TEST_LOVTEST_PRIM ,但您的问题分别将它们分别标记为LOVPRIM
  2. Your query uses CATEGRY , but your question defines the table with field, CATEGORY 您的查询使用CATEGRY ,但是您的问题使用字段CATEGORY定义了表

在CATEGORY上具有索引,COLUMN_LKP将避免全表扫描,并在您拥有巨大数据集的情况下更快地获取结果。

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

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