我使用PostgreSQL 9.6,我的表架构如下:department, key, value1, value2, value3, ...
每个部门都有数亿个唯一密钥,但所有部门的密钥集大致相同。某些部门可能不存在某些键,但这种情况很少见。
我想准备一份报告,指出两个部门指出每个键值的差异(比较涉及一些仅基于键值的逻辑)。
我的第一个方法是在python中编写一个外部工具:
SELECT * FROM my_table WHERE department = 'ABC' ORDER BY key;
SELECT * FROM my_table WHERE department = 'XYZ' ORDER BY key;
它工作正常,但我认为在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;
VS
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 :(得分: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';
第一部分涉及所有常见案例,两个工会拿起缺失值。我原本以为这会比光标方法快得多。
答案 1 :(得分: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;