我有一个Postgre SQL数据库表,其中包含超过500万个条目。 还有一个包含100,000个条目的CSV文件。
我需要运行一个查询来从DB获取与CSV文件数据相关的数据。
然而,根据每个人的理解和我自己的经验,这种查询需要很长时间才能完成。 (根据我的猜测,超过6个小时)
根据最新的调查结果和工具,我们是否有更好,更快的解决方案来执行同样的任务?
答案 0 :(得分:6)
fast lane:创建一个匹配CSV文件结构的temporary table(为方便起见,可能使用现有表作为模板)并使用COPY
:
CREATE TEMP TABLE tmp(email text);
COPY tmp FROM 'path/to/file.csv';
ANALYZE tmp; -- do that for bigger tables!
我假设 CSV中的电子邮件是唯一的,您没有指定。如果不是,那么 make 就是唯一的:
CREATE TEMP TABLE tmp0
SELECT DISTINCT email
FROM tmp
ORDER BY email; -- ORDER BY cheap in combination with DISTINCT ..
-- .. may or may not improve performance additionally.
DROP TABLE tmp;
ALTER TABLE tmp0 RENAME TO tmp;
<击>
对于您的特定情况,电子邮件中的唯一索引是有序的。
在加载和清理数据之后创建索引会更有效。通过这种方式,如果存在欺骗行为,您还可以阻止COPY
以独特的违规行为挽救:
CREATE UNIQUE INDEX tmp_email_idx ON tmp (email);
击> <击> 撞击>
第二个想法,如果您所做的只是更新大表,那么不根本不需要临时表上的索引。它将按顺序读取。
是DB表使用主键编制索引。
在这种情况下唯一相关的索引:
CREATE INDEX tbl_email_idx ON tbl (email);
如果可能,请CREATE UNIQUE INDEX ...
。
按照以后评论中的详细说明更新您的表格:
UPDATE tbl t
SET ...
FROM tmp
WHERE t.email = tmp.email;
所有这些都可以很容易地包装到plpgsql或sql函数中
请注意,如果要对文件名进行参数化,COPY
需要plpgsql函数中带EXECUTE
的动态SQL。
默认情况下,会话结束时会自动删除临时表
相关回答:
How to bulk insert only new rows in PostreSQL
答案 1 :(得分:2)
只是Erwin回答的一小部分内容 - 如果您只想查看csv文件中的电子邮件,代码可能是这样的:
create temp table tmp_emails (email text primary key);
copy tmp_emails from 'path/emails.csv';
analyze tmp_emails;
update <your table> set
...
from <your table> as d
where exists (select * from tmp_emails as e where e.email = d.email);
我认为可能有可能创建表返回函数来读取你的csv和 称之为:
update <your table> set
...
from <your table> as d
where exists (select * from csv_func('path/emails.csv') as e where e.email = d.email);
但是我没有在这里安装postgresql来尝试,我会稍后再做
答案 2 :(得分:0)
如果我理解正确,你的CSV文件包含一些字段,包含KEY,用于搜索PostgreSQL表。
我不知道您可以使用哪种编程语言来完成此任务,但一般情况下,您必须解决速度问题:
第一种方法,编程:
第二种方法,自然sql:
您选择的方式取决于您的实际任务。例如,根据我的经验,我必须创建接口以将价格列表加载到数据库中,并且在实际加载之前,需要显示导入的XLS文件,其中包含有关“当前”和“新”价格的信息,并且因为大尺寸的XLS文件,需要分页,因此,KEY IN(1,2,3,4,5,6)的变体最适合。