2

我有一个 Postgre SQL 数据库表,其中包含超过 500 万个条目。还有一个包含 100,000 个条目的 CSV 文件。

我需要运行查询以从数据库中获取与 CSV 文件数据相关的数据。

但是根据大家的理解和我自己的经验,这种查询需要很长时间才能完成。(根据我的猜测,超过 6 小时)

因此,根据最新的发现和工具,我们是否有更好、更快的解决方案来执行相同的任务?

4

3 回答 3

6

快速通道:创建一个与 CSV 文件结构匹配的临时表(为方便起见,可能使用现有表作为模板)并使用COPY

批量加载

CREATE TEMP TABLE tmp(email text);

COPY tmp FROM 'path/to/file.csv';
ANALYZE tmp;                       -- do that for bigger tables!

假设CSV 中的电子邮件是唯一的,您没有指定。如果不是,请将它们设为唯一:

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);

再想一想,如果您所做的只是更新大表,那么您根本不需要临时表上的索引。它将被顺序读取。

是的,数据库表是使用主键索引的。

在这种情况下唯一相关的索引:

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 函数中使用动态 SQL 。EXECUTE

默认情况下,临时表会在会话结束时自动删除。
相关答案:
如何在 PostreSQL 中仅批量插入新行

于 2013-08-22T07:49:32.817 回答
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可以试试,以后再做

于 2013-08-22T08:15:03.410 回答
0

如果我对您的理解正确,您的 CSV 文件包含一些字段,其中包含 KEY,用于搜索您的 PostgreSQL 表。

我不知道您可以使用哪种编程语言来完成此任务,但总的来说,您必须解决速度问题:

第一种方法,编程:

  1. 您需要将 CSV 文件加载到内存中,即使您的 CSV 每行有 500 个字节,也只需要 100000 * 500 = 50 兆字节的 RAM
  2. 您需要为 CSV 的 KEY 字段构建一些搜索索引 - 例如,在 PHP 中,您可以构建数组,并将键设置为您的 KEY 字段值。在 C++ 中,您可以创建某种 HASH 表,这些表由 STD lib 广泛提供,其他编程语言会为您提供它的变体。
  3. PostgreSQL 中的表应该由与您的 KEY 字段匹配的字段索引。
  4. 使用加载在内存中的 csv 数组来构造查询,例如 "SELECT * FROM table WHERE key IN(1,2,3,4,5,6,7,8,9)" ,其中 "1,2,3,4 ...” - 是您的 KEY 表单 CSV 的一部分(例如,一百)

第二种方法,自然sql:

  1. 创建表并将 CSV 加载到其中
  2. 在用于搜索的字段上创建索引
  3. 在 5Millions 表上创建索引
  4. 用户 JOIN 获取链接表数据

您将选择的方式取决于您的实际任务。例如,根据我的经验,我必须制作接口来将价格表加载到数据库中,并且在实际加载之前,需要显示导入的 XLS 文件,其中包含有关“当前”和“新”价格的信息,并且,因为大尺寸的 XLS 文件,在哪里需要分页,所以,带有 KEY IN (1,2,3,4,5,6) 的变体最适合。

于 2013-08-22T07:58:14.070 回答