簡體   English   中英

通過唯一鍵優化多個內部自聯接

[英]Optimization of multiple inner self-joins by unique key

假設我有一些帶有事務的表X ,其中CUSTOMER_ID是主鍵。

我也有數百個“功能”(就機器學習而言),即對該表X的查詢文本。 所有這些查詢就像:

查詢1:

SELECT
X.CUSTOMER_ID,
WHEN(X.GENDER = "F" AND X.IS_PREGNANT = TRUE) THEN 1 OTHERWISE 0 AS WILL_BUY_FOR_KIDS
FROM X

查詢xxx:

SELECT
X.CUSTOMER_ID,
WHEN(X.GENDER = "M" AND X.AVG_AMOUNT > 1000) THEN 1 OTHERWISE 0 AS RICH_DUDE
FROM X


任務是生成具有從X表計算出的所有“功能”的表。 因此,我需要使用“功能”查詢的文本(以編程方式)創建輸出查詢的文本。 就像是:

SELECT
*
FROM SOME_QUERY_1
INNER JOIN SOME_QUERY_X
ON SOME_QUERY_1.CUSTOMER_ID = SOME_QUERY_X.CUSTOMER_ID
...

當內部自我連接數百個子查詢時,上述輸出查詢可能會非常慢。 顯然,如果SQL引擎將該查詢“重寫”為類似(避免連接)的內容,那將很酷:

SELECT
CUSTOMER_ID,
WHEN(X.GENDER = "F" AND X.IS_PREGNANT = TRUE) THEN 1 OTHERWISE 0 AS WILL_BUY_FOR_KIDS,
WHEN(X.GENDER = "M" AND X.AVG_AMOUNT > 1000) THEN 1 OTHERWISE 0 AS RICH_DUDE,
.....
FROM X


幾個問題:

  1. 有沒有可以進行上述優化的SQL引擎(MySQL,PostgreSQL等)?
  2. 使用通用的數值代數,我們已經證明了可以簡化表達式的規則(例如: (a + b) * a = a^2 + b*a )。 關系代數有這樣的規則嗎?

看來Oracle的優化程序可以完成這項工作。

drop table x;
create table x (a int primary key,b int);

select  x0.b,x1.b,x2.b,x3.b,x4.b,x5.b,x6.b,x7.b,x8.b,x9.b

from         (select x.a,x.b from x) x0
        join (select x.a,x.b from x) x1 on x1.a = x0.a
        join (select x.a,x.b from x) x2 on x2.a = x0.a
        join (select x.a,x.b from x) x3 on x3.a = x0.a
        join (select x.a,x.b from x) x4 on x4.a = x0.a
        join (select x.a,x.b from x) x5 on x5.a = x0.a
        join (select x.a,x.b from x) x6 on x6.a = x0.a
        join (select x.a,x.b from x) x7 on x7.a = x0.a
        join (select x.a,x.b from x) x8 on x8.a = x0.a
        join (select x.a,x.b from x) x9 on x9.a = x0.a
;        

注意執行計划中的9 ELIMINATE_JOIN

--------------------------------------------------------------------------      
| Id  | Operation         | Name | Rows  | Bytes | Cost (%CPU)| Time     |      
--------------------------------------------------------------------------      
|   0 | SELECT STATEMENT  |      |     1 |    26 |     2   (0)| 00:00:01 |      
|   1 |  TABLE ACCESS FULL| X    |     1 |    26 |     2   (0)| 00:00:01 |      
--------------------------------------------------------------------------      

Query Block Name / Object Alias (identified by operation id):                   
-------------------------------------------------------------                   

PLAN_TABLE_OUTPUT                                                              
--------------------------------------------------------------------------------

   1 - SEL$44564B95 / X@SEL$2                                                   

Outline Data                                                                    
-------------                                                                   

  /*+                                                                           
      BEGIN_OUTLINE_DATA                                                        
      FULL(@"SEL$44564B95" "X"@"SEL$2")                                         
      OUTLINE(@"SEL$3")                                                         
      OUTLINE(@"SEL$2")                                                         
      OUTLINE(@"SEL$1")                                                         
      MERGE(@"SEL$3")                                                           
      MERGE(@"SEL$2")                                                           
      OUTLINE(@"SEL$5428C7F1")                                                  
      OUTLINE(@"SEL$5")                                                         
      OUTLINE(@"SEL$4")                                                         
      MERGE(@"SEL$5428C7F1")                                                    
      MERGE(@"SEL$5")                                                           
      OUTLINE(@"SEL$730B2DEF")                                                  
      OUTLINE(@"SEL$7")                                                         
      OUTLINE(@"SEL$6")                                                         
      MERGE(@"SEL$730B2DEF")                                                    
      MERGE(@"SEL$7")                                                           
      OUTLINE(@"SEL$DE510E9C")                                                  
      OUTLINE(@"SEL$9")                                                         
      OUTLINE(@"SEL$8")                                                         
      MERGE(@"SEL$DE510E9C")                                                    
      MERGE(@"SEL$9")                                                           
      OUTLINE(@"SEL$6C54F645")                                                  
      OUTLINE(@"SEL$11")                                                        
      OUTLINE(@"SEL$10")                                                        
      MERGE(@"SEL$6C54F645")                                                    
      MERGE(@"SEL$11")                                                          
      OUTLINE(@"SEL$5E3B1022")                                                  
      OUTLINE(@"SEL$13")                                                        
      OUTLINE(@"SEL$12")                                                        
      MERGE(@"SEL$5E3B1022")                                                    
      MERGE(@"SEL$13")                                                          
      OUTLINE(@"SEL$D60B40D8")                                                  
      OUTLINE(@"SEL$15")                                                        
      OUTLINE(@"SEL$14")                                                        
      MERGE(@"SEL$D60B40D8")                                                    
      MERGE(@"SEL$15")                                                          
      OUTLINE(@"SEL$B8655000")                                                  
      OUTLINE(@"SEL$17")                                                        
      OUTLINE(@"SEL$16")                                                        
      MERGE(@"SEL$B8655000")                                                    
      MERGE(@"SEL$17")                                                          
      OUTLINE(@"SEL$EC740ABE")                                                  
      OUTLINE(@"SEL$19")                                                        
      OUTLINE(@"SEL$18")                                                        
      MERGE(@"SEL$EC740ABE")                                                    
      MERGE(@"SEL$19")                                                          
      OUTLINE(@"SEL$7AC5A3AA")                                                  
      OUTLINE(@"SEL$20")                                                        
      MERGE(@"SEL$7AC5A3AA")                                                    
      OUTLINE(@"SEL$F6D45FB3")                                                  
      ELIMINATE_JOIN(@"SEL$F6D45FB3" "X"@"SEL$17")                              
      ELIMINATE_JOIN(@"SEL$F6D45FB3" "X"@"SEL$15")                              
      ELIMINATE_JOIN(@"SEL$F6D45FB3" "X"@"SEL$13")                              
      ELIMINATE_JOIN(@"SEL$F6D45FB3" "X"@"SEL$11")                              
      ELIMINATE_JOIN(@"SEL$F6D45FB3" "X"@"SEL$9")                               
      ELIMINATE_JOIN(@"SEL$F6D45FB3" "X"@"SEL$7")                               
      ELIMINATE_JOIN(@"SEL$F6D45FB3" "X"@"SEL$5")                               
      ELIMINATE_JOIN(@"SEL$F6D45FB3" "X"@"SEL$3")           
      OUTLINE(@"SEL$5A225B26")                                                  
      ELIMINATE_JOIN(@"SEL$5A225B26" "X"@"SEL$19")                              
      OUTLINE_LEAF(@"SEL$44564B95")                                             
      ALL_ROWS                                                                  
      DB_VERSION('11.2.0.2')                                                    
      OPTIMIZER_FEATURES_ENABLE('11.2.0.2')                                     
      IGNORE_OPTIM_EMBEDDED_HINTS                                               
      END_OUTLINE_DATA                                                          
  */                                                                            

Column Projection Information (identified by operation id):                     

   1 - "X"."B"[NUMBER,22]                                                       

Note                                                                            
-----                                                                           
   - dynamic sampling used for this statement (level=2)                         

首先,您應將查詢編寫為:

SELECT X1.A * 2, // Some operation on X1.A
       X2.B / 2 // Some operation on X2.B
FROM X X1 JOIN
     X X2
     ON X1.C = X2.C;

子查詢沒有提供任何值(但我稍后會再講)。

如果C被聲明為unique (或primary key ),則該字段上有一個索引。 我很確定每個數據庫仍然會執行JOIN ,但這確實非常快:

  • 處理記錄( X1 )並找到C
  • 索引中的查找C
  • 返回到內存中已經存在的記錄以獲取X2

與首先讀取數據相比,用於索引的額外開銷不是很大的負擔。

使用您編寫的查詢,大多數數據庫都足夠聰明,仍然可以進行此優化-他們只是忽略了子查詢。 MySQL是一個例外。 它實際上實現了子查詢,因此您編寫的版本可能會令人討厭地緩慢-實現也會失去使用索引的能力。 但是,重寫應該可以。

您可能會問,為什么數據庫對此沒有優化。 好吧,數據庫開發人員更專注於優化寫得好的查詢,而不是優化寫得不好的查詢。 如果不需要JOIN ,那么查詢write應該知道這一點。 (實際上, JOIN確實有一種用途,它過濾掉NULL值。)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM