Какой самый быстрый способ вставить данные в PostgreSQL в таблицу N: M? - PullRequest
1 голос
/ 31 октября 2011

У меня есть приложение, которому нужно вставить много строк в базу данных, но в данный момент вставка идет слишком медленно, я хочу знать, каковы лучшие методы, чтобы ускорить вставку до максимума.

Ситуация в каждой вставке, мне нужно узнать идентификатор токена, и для этого я поместил SELECT внутри вставки.

Что может быть лучшим решением для максимальной скорости вставки в таблицу textBlockHasToken, включая SQL и Java?

Редактировать: В данный момент это работает, но у меня большой поток данных. Некоторые числа, 100 000 различных строк в таблице токенов и 2 миллиона строк в textBlockHasToken.

У меня есть три таблицы и два 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 ]

5 голосов
/ 31 октября 2011

Лучшее, что вы можете сделать, - это убедиться, что все переменные WHERE имеют индексы, связанные с ними.Они автоматически создаются для первичных ключей;убедитесь, что столбцы внешнего ключа также имеют индексы.

Другое соображение - пакетные запросы.Не делайте сетевой обход для каждой вставки;Пакуйте их вместе кусками и передайте каждый кусок.Это также будет означать меньшее количество сетевых обращений и управляемых журналов транзакций.

3 голосов
/ 01 ноября 2011
  • не используйте зарезервированные слова в качестве идентификатора (текст, дата)
  • (пожалуйста, не используйте 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;
1 голос
/ 01 ноября 2011

duffymo уже упоминал о пакетных обновлениях. Просто чтобы быть уверенным, я бы добавил:

  • Вы экспериментировали / измеряли разные размеры одной транзакции?
  • Вы уже используете и повторно используете подготовленные заявления?
  • Экспериментировали ли вы с измерением "INSERT INTO token ... RETURNING id" и вводили это непосредственно во второй оператор вставки?

Но, ничего не зная о существующем коде, все это очень похоже на хрустальный шар.

1 голос
/ 31 октября 2011

Я полностью согласен с duffymo, но я бы также добавил, Функция COPY в Postgres - это удобный способ импорта данных.

Конечно, это не всегда возможно сделать, особенно изнутри кода. вот почему я также согласен с duffymo: если вам НУЖНО сделать это из кода на отдельной машине, сделайте то, что сказал duffymo.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...