2017-07-25 33 views
0

我使用PostgreSQL 9.6和我的表架構如下:department, key, value1, value2, value3, ...每個部門都有數以億計的唯一鍵,但鍵組或多或少相同的所有部門。某些部門可能不存在某些密鑰,但這種情況很少見。如何有效地比較一個大表的兩個行子集?

我想準備一份報告,對兩個部門指出了每個按鍵(包括比較僅基於鍵值一些邏輯)在價值觀的差異。

我的第一種方法是用Python語言編寫的外部工具:

  1. 創建一個服務器端遊標查詢:SELECT * FROM my_table WHERE department = 'ABC' ORDER BY key;
  2. 創建另一個服務器端遊標查詢:SELECT * FROM my_table WHERE department = 'XYZ' ORDER BY key;
  3. 迭代在兩個遊標上,並比較這些值。

它工作得很好,但我認爲在PostgreSQL中執行存儲過程內的比較會更高效。我編寫了一個將兩個遊標作爲參數的存儲過程,對它們進行迭代並比較這些值。任何差異都寫入臨時表中。最後,外部工具在臨時表上迭代 - 不應該有很多行。

我認爲後一種方法會更有效,因爲它不需要數據庫外部傳輸大量數據。 令我驚訝的是,它竟然是近40%速度較慢。

爲了分離我迭代相比的光標在存儲過程中的性能的問題,並在python:

FETCH cur_1 INTO row_1; 
WHILE (row_1 IS NOT NULL) LOOP 
    rows = rows + 1; 
    FETCH FROM cur_1 INTO row_1; 
END LOOP; 

conn = psycopg2.connect(PG_URI) 
cur = conn.cursor('test') 
cur.execute(query) 
cnt = 0 
for row in cur: 
    cnt += 1 

查詢是在兩種情況下是相同的。再次,外部工具速度更快。 我的假設是,這是因爲存儲過程一個接一個地提取行(FETCH FROM curs_1 INTO row_1),而應用程序獲取2000批次的行。但是我找不到一種方法從PgSQL中的遊標中獲取一批行程序。因此,我無法檢驗這個假設。

所以我的問題是它能夠加速我的存儲過程?

是什麼這樣的問題最好的方法?

+0

一些關鍵構成部分缺失,以獲得最佳的答案:確切的表定義('CREATE TABLE '顯示數據類型和約束的語句)。有關數據分佈的更多信息:每個'(部門,關鍵)'有多少行:min,avg,max。現有索引。 「指出差異」在普通英語中聽起來不錯,但沒有確定比較和結果的確切要求。更加詳細一些。 –

回答

0

爲什麼你不能做自聯接而不是使用遊標?例如:

SELECT t1.key, t1.value1 - t2.value1 as diff1, 
t1.value2 - t2.value2 as diff2, ... 
FROM my_table t1 inner join my_table t2 on t1.key = t2.key 
WHERE t1.department = 'XYZ' and t2.department = 'ABC' 
UNION 
SELECT t1.key, t1.value1 as diff1, 
t1.value2 as diff2, ... 
FROM my_table t1 WHERE NOT EXISTS (SELECT 1 FROM my_table t2 WHERE 
t1.key = t2.key AND t2.dept = 'ABC') AND t1.dept = 'XYZ' 
UNION 
SELECT t1.key, t1.value1 as diff1, 
t1.value2 as diff2, ... 
FROM my_table t1 WHERE NOT EXISTS (SELECT 1 FROM my_table t2 WHERE 
t1.key = t2.key AND t2.dept = 'XYZ') AND t1.dept = 'ABC'; 

第一部分處理所有常見情況,兩個工會提取缺失的值。我原以爲這會比光標方法快得多。

0

這可能會更快,因爲它只會返回那些在值的至少一個方面不同行:

select * 
from ( 
    SELECT key, value1, value2, value3 
    FROM my_table 
    WHERE department = 'ABC' 
) d1 
    full join (
    SELECT key, value1, value2, value3 
    FROM my_table 
    WHERE department = 'XYZ' 
) d2 using (key) 
where d1 is distinct from d2;