将海量 CSV 文件读入 Oracle 表
Posted
技术标签:
【中文标题】将海量 CSV 文件读入 Oracle 表【英文标题】:Reading A Massive CSV file into an Oracle table 【发布时间】:2019-11-03 00:12:45 【问题描述】:我有一个包含超过 200,000 行的巨大 CSV 文件。每行都有一个评论 ID、酒店 ID、评论日期和评论本身。评论栏引起了问题。有些评论很长,超过 2000 字节,因此会导致错误:
ORA-20000:ORU-10027:缓冲区溢出,限制为 20000 字节。
我能做些什么来解决这个问题吗?这是我当前的代码:
DECLARE
F UTL_FILE.FILE_TYPE;
v_Line VARCHAR2(2000);
v_ReviewID NUMBER;
v_HotelID VARCHAR2(2000);
v_ReviewDate VARCHAR(2000);
v_ReviewName CLOB;
v_Review CLOB;
BEGIN
F := UTL_FILE.FOPEN ('REVIEW_READ', 'Review.csv', 'R', 30000);
IF UTL_FILE.IS_OPEN(F) THEN
LOOP
BEGIN
DBMS_OUTPUT.PUT_LINE('Start');
UTL_FILE.GET_LINE(F, v_Line);
v_ReviewID := REGEXP_SUBSTR(v_Line, '[^,]+', 1, 1);
v_HotelID := REGEXP_SUBSTR(v_Line, '[^,]+', 1, 2);
v_ReviewDate := REGEXP_SUBSTR(v_Line, '[^,]+', 1, 3);
v_ReviewName := REGEXP_SUBSTR(v_Line, '[^,]+', 1, 4);
v_Review := REGEXP_SUBSTR(v_Line, '[^,]+', 1, 5);
INSERT INTO Review
VALUES(v_ReviewID, v_HotelID, v_ReviewDate, v_ReviewName, v_Review);
DBMS_OUTPUT.PUT_LINE(v_Line);
IF v_Line IS NULL THEN
EXIT;
END IF;
COMMIT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
EXIT;
END;
END LOOP;
END IF;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLERRM);
UTL_FILE.FCLOSE(F);
END;
【问题讨论】:
请提及您正在使用的数据库软件:Oracle? 是的,我正在使用 Oracal 将评论文本的数据类型更改为CLOB
。
我进行了上述编辑,但我仍然恢复了以下错误:ORA-20000:ORU-10027:缓冲区溢出,限制为 20000 字节。评论长短不一,有些真的很大。有没有办法读取其中的一部分然后解析它然后读取其余部分?
@NathanC 我已将此错误消息添加到您的问题中。我认为这是您遇到的主要问题,因为您提到了“缓冲区溢出错误”,但如果 VARCHAR2 变量或表的列对于您要加载的内容来说不够大,也可能会出现问题。在声明列时使用tablename.columnname%type
语法也是一个好主意,这样您就知道一切都是同步的。
【参考方案1】:
您的代码存在 2 个问题。 @Steve Friedl 已经提到了一个。另一个如下:
如果您在PL/SQL
中使用大量dbms_output.put_line
且缓冲量很小,则会出现ORU-10027
。
如果您只是在调试,那么您应该将其设置为很大(dbms_output.enable(10000000) 是传统的,尽管从 10g 开始它可以不受限制。
所以如果你在你的代码中评论这一行
DBMS_OUTPUT.PUT_LINE(V_LINE);
并将此 DBMS_OUTPUT.PUT_LINE('Start');
置于循环之外,它应该可以正常工作。
【讨论】:
【参考方案2】:我不知道这个数据库系统,但它看起来像这样一行:
v_Review := REGEXP_SUBSTR(V_LINE, '[^,]+', 1, 5);
通过尝试将过长的字符串分配给 2000 限制 v_Review
给您带来了问题。也许使用SUBSTR
只收集该字符串的前 2000 个字符可能有效?
v_Review := SUBSTR( REGEXP_SUBSTR(V_LINE, '[^,]+', 1, 5), 0, 2000 ); // maybe?
【讨论】:
这不起作用。我仍然得到同样的错误:ORA-20000: ORU-10027: buffer overflow, limit of 20000 bytes【参考方案3】:尝试删除所有dbms_output
行并重新检查结果。我的猜测是你只是把一个很长的输出放到缓冲区中。
此外,如果您必须将一次性 CSV 文件加载到 Oracle 数据库中,请查看 sqlldr
实用程序(例如,https://www.orafaq.com/wiki/SQL*Loader_FAQ)。它为您完成所有工作,您只需创建一个目标表并进行一些设置。
【讨论】:
以上是关于将海量 CSV 文件读入 Oracle 表的主要内容,如果未能解决你的问题,请参考以下文章
如何将数据从单个 csv/excel 文件传输到多个 oracle 表