Слияние баз данных SQLite сводит меня с ума. Помогите? - PullRequest
1 голос
/ 25 ноября 2011

У меня есть 32 базы данных SQLite (3.7.9) с 3 таблицами в каждой, которые я пытаюсь объединить, используя идиому, который я нашел в другом месте (каждая БД имеет одну и ту же схему):

attach db1.sqlite3 as toMerge;
insert into tbl1 select * from toMerge.tbl1;
insert into tbl2 select * from toMerge.tbl2;
insert into tbl3 select * from toMerge.tbl3;
detach toMerge;

и повторное полоскание для всего набора баз данных.Я делаю это, используя python и модуль sqlite3:

  for fn in filelist:

    completedb = sqlite3.connect("complete.sqlite3")
    c = completedb.cursor()

    c.execute("pragma synchronous = off;")
    c.execute("pragma journal_mode=off;")

    print("Attempting to merge " + fn + ".")
    query = "attach '" + fn + "' as toMerge;"
    c.execute(query)

    try:
        c.execute("insert into tbl1 select * from toMerge.tbl1;")
        c.execute("insert into tbl2 select * from toMerge.tbl2;")
        c.execute("insert into tbl3 select * from toMerge.tbl3;")
        c.execute("detach toMerge;")
        completedb.commit()
    except sqlite3.Error as err:
        print "Error! ", type(err), " Error msg: ", err
        raise

2 таблиц довольно маленькие, всего 50K строк на дБ, а третья (tbl3) больше, около 850 - 900K строк.Теперь, что происходит, так это то, что вставки постепенно замедляются, пока я не доберусь до четвертой базы данных, когда они почти остановятся (порядка одного или двух мегабайт в размере файла, добавляемом каждые 1-3 минуты в объединенную базу данных).В случае, если это был python, я даже пытался выгружать таблицы как INSERT (.insert; .out foo; sqlite3 complete.db здесь ) и объединять их в bashскрипт, использующий интерфейс командной строки sqlite3 для выполнения работы напрямую, но я получаю точно такую ​​же проблему.

Настройка таблицы tbl3 не слишком сложна - текстовое поле, содержащее UUID, два целых числа и четыре действительных значения.Меня беспокоит то, что это количество строк, потому что я столкнулся с точно такой же проблемой в одном и том же месте (около четырех баз данных), когда отдельные базы данных были на порядок больше с точки зрения размера файла при том же количестве строк(Я значительно урезал содержимое таблицы tbl3, сохранив сводную статистику вместо необработанных данных).Или, может быть, так я выполняю операцию?Может ли кто-нибудь пролить свет на эту проблему, с которой я столкнулся, прежде чем выбросить что-то в окно?

Ответы [ 2 ]

1 голос
/ 25 ноября 2011

Попробуйте добавить или удалить индексы / первичный ключ для таблицы большего размера.

1 голос
/ 25 ноября 2011

Вы не упомянули операционную систему, которую вы использовали, или размеры файлов БД. В зависимости от версии Windows могут возникнуть проблемы с файлами размером более 2 ГБ.

В любом случае, поскольку это прославленный пакетный скрипт, почему бы не избавиться от цикла for, получить имя файла из sys.argv, а затем просто запустить его один раз для каждого слияния БД. Таким образом, вам никогда не придется иметь дело с проблемами с памятью, если вы будете делать слишком много в одном процессе.

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

c.close()
completedb.close()

Вы говорите, что то же самое происходит, когда вы следуете этому процессу, используя CLI и выходя после каждого дБ. Я предполагаю, что вы имеете в виду Python CLI, а выход означает, что вы выходите и перезапускаете Python. Если это так, и проблема возникает в каждой четвертой базе данных, значит, с вашей разделяемой библиотекой SQLITE что-то не так. Не должно быть такого состояния.

Если бы я был на вашем месте, я бы прекратил использовать attach и просто открыл несколько соединений в Python, а затем переместил данные в пакетах по 1000 записей на коммит. Это будет медленнее, чем ваша техника, потому что все данные перемещаются в объекты Python и из них, но я думаю, что это также будет более надежным. Откройте полную базу данных, затем зациклите, открыв вторую базу данных, скопировав и закрыв вторую базу данных. Для копирования я бы использовал OFFSET и LIMIT в операторах SELECT, чтобы обработать пакеты из 100 записей, затем зафиксировать, а затем повторить. На самом деле, я бы также подсчитывал завершенные записи b и вторые записи базы данных перед копированием, а затем после копирования подсчитывал записи completeb, чтобы убедиться, что я скопировал ожидаемую сумму. Кроме того, вы будете следить за значением следующего OFFSET, и я запишу его в текстовый файл сразу после фиксации, чтобы я мог прервать и перезапустить процесс в любое время, и он продолжит с того места, где он остановился.

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