Файл вкладки импорта SQLite: .import выполняет одну вставку на строку или группирует их по транзакции? - PullRequest
4 голосов
/ 08 июля 2011

Я импортирую миллионы строк из файла вкладок, а вкладки SQLite .import .mode работают очень медленно. У меня есть три индекса, поэтому, вероятно, медлительность происходит от индексации. Но сначала я хотел бы проверить, что .import добавляет строки, объединяющие партии / все из них в один коммит. Мне не удалось найти документацию о том, как работает .import. Кто-нибудь знает? Если проблема с индексом (у меня эта проблема была раньше с mysql), как я могу отключить его и переиндексировать в конце .import?

[Обновление 1]

После комментария @sixfeetsix.

Моя схема:

CREATE TABLE ensembl_vf_b36 (
        variation_name  varchar(20),
        chr     varchar(4),
        start   integer,
        end     integer,
        strand  varchar(5),
        allele_string    varchar(3),
        map_weight      varchar(2),
        flags           varchar(50),
        validation_status       varchar(100),
        consequence_type        varchar(50)
);
CREATE INDEX pos_vf_b36_idx on ensembl_vf_b36 (chr, start, end);

данные:

rs35701516      NT_113875       352     352     1       G/A     2       NULL    NULL    INTERGENIC
rs12090193      NT_113875       566     566     1       G/A     2       NULL    NULL    INTERGENIC
rs35448845      NT_113875       758     758     1       A/C     2       NULL    NULL    INTERGENIC
rs17274850      NT_113875       1758    1758    1       G/A     2       genotyped       cluster,freq    INTERGENIC

В этой таблице 15_608_032 записей

А это статистика

 $  time sqlite3 -separator '   ' test_import.db '.import variations_build_36_ens-54.tab ensembl_vf_b36'

real    29m27.643s
user    4m14.176s
sys     0m15.204s

[Обновление 2]

@ sixfeetsix имеет хороший ответ, и если вы читаете это, вас также заинтересует

Более быстрые массовые вставки в sqlite3?

Sqlite3: отключение индекса первичного ключа при вставке?

[update3] Решение от 30 мин. -> 4 мин.

Даже при всех оптимизациях (см. Принятый ответ) все еще требуется почти 30 минут, но если индексы не используются и не добавляются в конце, тогда общее время составляет 4 минуты:

-- importing without indexes:
       real    2m22.274s
       user    1m38.836s
       sys     0m4.850s

 -- adding indexes
     $  time sqlite3 ensembl-test-b36.db < add_indexes-b36.sql

     real    2m18.344s
     user    1m26.264s
     sys     0m6.422s

1 Ответ

6 голосов
/ 10 июля 2011

Я полагаю, что медлительность действительно заключается в построении индекса, поскольку все больше и больше записей добавляется. В зависимости от имеющейся у вас оперативной памяти, вы можете указать sqlite использовать достаточно памяти, чтобы вся эта деятельность по созданию индекса выполнялась в памяти (то есть без всех операций ввода-вывода, которые могли бы произойти в противном случае с меньшим объемом памяти).

Для 15M записей я бы сказал, что вы должны установить размер кэша на 500000.

Вы также можете указать sqlite хранить журнал транзакций в памяти.

Наконец, вы можете установить синхронное на ВЫКЛ, чтобы sqlite никогда не дожидалась записи на диск.

Используя это, я смог разделить время, необходимое для импорта 15M записей на 5 (14 минут до 2,5) с записями из случайных GUID, разделенных на 5 столбцов, используя три средних столбца в качестве индекса:

b40c1c2f    912c    46c7    b7a0    3a7d8da724c1
9c1cdf2e    e2bc    4c60    b29d    e0a390abfd26
b9691a9b    b0db    4f33    a066    43cb4f7cf873
01a360aa    9e2e    4643    ba1f    2aae3fd013a6
f1391f8b    f32c    45f0    b137    b99e6c299528

Поэтому, чтобы попробовать это, я предлагаю вам поместить все инструкции в некоторый файл, скажем import_test:

pragma journal_mode=memory;
pragma synchronous=0;
pragma cache_size=500000;
.mode tabs
.import variations_build_36_ens-54.tab ensembl_vf_b36

Тогда попробуйте:

time sqlite3 test_import.db < import_test

EDIT

Это ответ на комментарии Пабло (ОП), следующий за этим ответом (его долго не помещать в качестве комментария): Мои (образованные) догадки таковы:

  1. Потому что .import не является sql как таковым, это не так уж много шума с транзакции, я даже склонен к думаю, что написано идти быстрее, чем если бы у вас было все это сделано за одну "нормальную" транзакцию; и
  2. Если у вас достаточно памяти для выделить, и вы создали свой среда, как я предполагаю, реальная (время) боров здесь читает квартиру файл, затем запись окончательного содержания базы данных, потому что случается между случается чрезвычайно быстро; то есть достаточно быстро, что там не так много времени, чтобы оптимизировать его когда вы сравниваете такой потенциал выигрывает с (вероятно) несжимаемым временем, затрачиваемым на дисковый ввод-вывод.

Если я ошибаюсь, я был бы рад услышать почему в свою пользу.

РЕДАКТИРОВАТЬ 2

Я провел сравнительный тест между наличием индекса во время .import и его добавлением сразу после завершения .import. Я использовал ту же технику генерации 15M записи из разделенных случайных UUID:

import csv, uuid
w = csv.writer(open('bla.tab', 'wb'), dialect='excel-tab')
for i in xrange(15000000):
    w.writerow(str(uuid.uuid4()).split('-'))

Затем я протестировал импорт с индексом, созданным до и после (здесь индекс создается после):

pragma journal_mode=memory;
pragma synchronous=0;
pragma cache_size=500000;
create table test (f1 text, f2 text, f3 text, f4 text, f5 text);
CREATE INDEX test_idx on test (f2, f3, f4);
.mode tabs
.import bla.tab test

Так вот время добавления индекса до :

[someone@somewhere ~]$ time sqlite3 test_speed.sqlite < import_test 
memory

real   2m58.839s
user   2m21.411s
sys    0m6.086s

А при добавлении индекса после :

[someone@somewhere ~]$ time sqlite3 test_speed.sqlite < import_test 
memory

real   2m19.261s
user   2m12.531s
sys    0m4.403s

Вы видите, как разница времени пользователя (~ 9 с) не учитывает разницу полного времени (~ 40 с)? Для меня это означает, что при создании индекса ранее происходил некоторый дополнительный ввод-вывод, и поэтому я ошибался, полагая, что все выполняется в памяти без дополнительных операций ввода-вывода.

Вывод: создайте индекс после, и у вас будет еще лучшее время импорта (как упоминал Донал).

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