哪个是在N:M表中在PostgreSQL中插入数据的最快方法?

时间:2011-10-31 19:13:07

标签: java sql postgresql

我有一个需要在数据库中插入大量行的应用程序,但目前插入速度太慢,我想知道什么是加快插入速度的最佳技术。

情况是在每次插入时,我需要发现令牌的id,为此,我将SELECT放在插入内。

对于加速textBlockHasToken表(包括SQL和Java)的最大插入,哪个可以是最佳解决方案?

编辑:目前有效,但我的数据流量很大。一些数字,令牌表中有100,000个不同的行,textBlockHasToken中有200万行。

我有这三个表和两个插入SQL:

-- Text blocks of the pages
CREATE TABLE textBlock(
    id                 INTEGER    PRIMARY KEY,
    pageId             INTEGER    REFERENCES page,
    text               VARCHAR    NOT NULL, 
    position           INTEGER    NOT NULL  
);

-- Tokens in the text blocks
CREATE TABLE token(
    id                 INTEGER    PRIMARY KEY,  
    text               VARCHAR    NOT NULL, 
    charType           VARCHAR    NOT NULL,
    grammar            VARCHAR    NOT NULL,
    category           VARCHAR[]  NOT NULL, 
    stopWord           BOOLEAN    NOT NULL    DEFAULT false,
    UNIQUE(text)
);

-- N:N relationship between textblock and token 
CREATE TABLE textBlockHasToken(
    textBlockId        INTEGER    REFERENCES textBlock NOT NULL,
    tokenId            INTEGER    REFERENCES token NOT NULL,
    sentence           INTEGER    NOT NULL,
    position           INTEGER    NOT NULL
);

-- Insert the token
INSERT INTO token(id,text,charType,grammar,category)
VALUES(nextval('tokenIdSqc'),?,?,?,?);

-- Insert in relationship in N:M
INSERT INTO textBlockHasToken(textblockId,tokenId,sentence,position)
VALUES(?,(SELECT id FROM token WHERE text = ?),?,?);

4 个答案:

答案 0 :(得分:5)

您可以做的最好的事情是确保所有WHERE变量都有与之关联的索引。它们是为主键自动创建的;确保外键列也有索引。

另一个考虑因素是批处理请求。不要为每个INSERT进行网络往返;将它们一起批处理并提交每个块。这意味着更少的网络往返次数和可管理的交易日志。

答案 1 :(得分:3)

  • 不要将保留字用作标识符(文本,日期)
  • (请不要使用MixedCaseIdentifiers)
  • 你的表定义不起作用。下面的那个确实有效。

-- Text blocks of the pages

DROP TABLE tmp.textblock CASCADE;
CREATE TABLE tmp.textblock
    ( id                 INTEGER    PRIMARY KEY
    , pageid             INTEGER    -- REFERENCES page
    , ztext               VARCHAR    NOT NULL
    , position           INTEGER    NOT NULL
    );

-- Tokens in the text blocks
DROP TABLE tmp.token CASCADE;
DROP SEQUENCE tmp.tokenidsqc;
CREATE SEQUENCE tmp.tokenidsqc;

CREATE TABLE tmp.token
    ( id                 INTEGER    PRIMARY KEY DEFAULT nextval('tmp.tokenidsqc')
    , ztext               VARCHAR    NOT NULL
    , chartype           VARCHAR    NOT NULL
    , grammar            VARCHAR    NOT NULL
    , category           VARCHAR  NOT NULL
    , stopword           BOOLEAN    NOT NULL    DEFAULT false
    , UNIQUE(ztext)
    );

-- N:N relationship between textblock and token 
DROP TABLE tmp.textblockhastoken CASCADE;
CREATE TABLE tmp.textblockhastoken
    ( textblockid        INTEGER    NOT NULL REFERENCES tmp.textblock(id)
    , tokenid            INTEGER    NOT NULL REFERENCES tmp.token(id)
    , sentence           INTEGER    NOT NULL
    , position           INTEGER    NOT NULL
    );

-- Insert the token
INSERT INTO tmp.token(ztext,chartype,grammar,category)
VALUES('foo' , 'T' , 'a', 'a' ), ('bar' , 'T' , 'a', 'a' );

SELECT * FROM tmp.token;

答案 2 :(得分:1)

我完全同意duffymo,但我还要补充一点,Postgres's COPY feature是导入数据的方式..

当然,这样做并不总是可行的,特别是在代码中。这就是为什么我也同意duffymo,如果你需要在一台单独的机器上用代码来做,那就去做duffymo说的。

答案 3 :(得分:1)

duffymo已经提到了批量更新。只是为了确保我会添加:

  • 您是否使用不同规模的一笔交易进行了实验/测量?
  • 您是否已经使用并重复使用预准备好的陈述?
  • 您是否使用“INSERT INTO token ... RETURNING id”进行实验/测量并将其直接输入第二个插入语句?

但是在不了解现有代码的情况下,这完全是水晶球猜测。