INSERT IGNORE在mysql模式下使用h2引发主键冲突

时间:2019-06-26 17:34:19

标签: java mysql database h2

我正在将Scopus数据抓取到h2文件数据库中。数据中有超过46,000,000条记录,每条记录都被视为不同的记录,这意味着要重复数百GB的数据(因此称为关系db)。为了减少所有这些数据的插入时间,我首先创建了一组没有约束的临时表,然后稍后使用SELECT DISTINCT和GROUP BY强制唯一性将数据复制到实际表中。

一个例外是文档表和引用的文档表。由于数据的格式,我可以保证每个记录都代表一个唯一的文档,因此我只需将它们插入到文档表中,然后再从引用的文档表中合并具有ID不在文档表中的行。

以下是相关代码:

CREATE TABLE document (docid varchar NOT NULL, title varchar, abstract varchar, docType varchar NULL, ref boolean);

CREATE TABLE refdoc (refid varchar NOT NULL, title varchar);

INSERT INTO document (docid, title, abstract, docType, ref)
VALUES ('2-s2.0-0000098715', 'title', 'abstract', 'ab', 'false');

INSERT INTO refdoc (refid, title)
VALUES ('2-s2.0-0000098715', 'title'),
VALUES ('2-s2.0-33947184743', 'title');

ALTER TABLE document
ADD PRIMARY KEY (docid);

ALTER TABLE document
ADD FOREIGN KEY (docType) REFERENCES doctype(abbrev);

INSERT IGNORE INTO document (docid, title, ref)
SELECT refid, title, 'true' FROM refdoc;

  • 创建文档表
  • 创建参考文档表
  • 将记录插入文档表中
  • 将两个记录插入refdoc表中,包括重复记录
  • 使用主键更改文档表
  • 使用外键更改文档表
  • 从refdoc插入与文档不冲突的行

INSERT IGNORE查询引发:org.h2.jdbc.JdbcSQLException:唯一索引或主键冲突:“ CONSTRAINT_INDEX_6 ON PUBLIC.DOCUMENT(DOCID)

我还尝试了使用WHERE NOT EXISTS:

INSERT INTO document (docid, title, ref)
SELECT refid, title, 'true'
FROM refdoc
WHERE NOT EXISTS (
SELECT refid FROM refdoc
INNER JOIN document
ON document.docid = refdoc.refid );

但是看来,试图联接未建立索引的表实际上是不可能的-我没有尝试过涉及联接的任何尝试。

作为最后的选择,我可以使用FileHashMap并转储refdoc表的内容,然后构造一个大型的PreparedStatement,例如:

INSERT INTO document (docid, title, ref)
SELECT ?, ?, 'true'
WHERE NOT EXISTS (
SELECT docid FROM document
WHERE docid = ? );

但我显然不愿意这样做,因为这将需要很长时间。

1 个答案:

答案 0 :(得分:0)

最后找到了一个不涉及构造100,000,000条记录的批处理语句的解决方案。问题是我需要强制执行以下操作:我要插入文档的refdocs不在文档表中,而且我只插入了refdoc表中的唯一行。在此之前,我所有的解决方案都无法避免冲突,无法强制执行唯一性或涉及对没有索引的表进行联接。

这是解决方案的SQL:

CREATE TABLE document (docid varchar NOT NULL, title varchar, abstract varchar, docType varchar NULL);

CREATE TABLE refdoc (refid varchar NOT NULL, title varchar);

INSERT INTO document (docid, title, abstract, docType)
VALUES ('2-s2.0-0000098715', 'title', 'abstract', 'ab');

INSERT INTO refdoc (refid, title)
VALUES ('2-s2.0-0000098715', 'title'),
VALUES ('2-s2.0-33947184743', 'title');

INSERT IGNORE INTO document (docid, title)
SELECT refid, MAX(title)
FROM refdoc
WHERE refid NOT IN (
SELECT docid FROM document )
GROUP BY refid;

ALTER TABLE document
ADD PRIMARY KEY (docid);

ALTER TABLE document
ADD FOREIGN KEY (docType) REFERENCES doctype(abbrev);

现在的逻辑是:

  • 创建文档表
  • 创建参考文档表
  • 将记录插入文档表中
  • 将两个记录插入refdoc表中,包括重复记录
  • 从refdoc插入与文档不冲突且唯一的行
  • 使用主键更改文档表
  • 使用外键更改文档表

这还有一个好处,就是直到插入完成后才索引文档表。

我仍然不清楚为什么我在没有主键的表上遇到主键约束冲突,但这听起来像是要作为错误报告提交给h2 github的东西。