2013-08-25 2 views
0

Я пишу программу, которая восстанавливает структурированные данные как отдельные записи из (поврежденного) файла и собирает результаты в базу данных sqlite.Как предотвратить добавление идентичных записей в базу данных SQL

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

Теперь, каждый раз, когда я запускаю свою программу с разными параметрами, она должна добавлять только новые (разные) найденные элементы в одну и ту же базу данных.

Это означает, что мне нужен быстрый способ определить, присутствует ли каждая восстановленная запись в БД или нет, чтобы добавить их, только если они еще не существуют в БД.

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

Но поскольку я добавляю 10000 записей, выполнение SELECT для каждой из этих записей кажется довольно неэффективным (медленным) для меня.

Интересно, есть ли более умный способ справиться с этим? I.e, есть ли способ сказать sqlite, что я не хочу дублировать записи, и поэтому он автоматически обнаруживает и отклоняет их? Я знаю об модификаторе UNIQUE, но это не так, потому что это относится только к одиночным столбцам, не так ли? Мне нужно было бы сказать, что комбинация COL1 + COL2 + COL3 должна быть уникальной. Есть ли способ сделать это?

Примечание: я никогда не хочу обновлять существующие записи. Я только хочу собрать набор разных записей.

Bonus часть - производительность

В классическом языке программирования, я хотел бы использовать словарь ключ-значение, где ключ является суммой всех значений записи, то. Аналогично, я мог бы рассчитать хэш-код для каждой добавленной записи и сначала посмотреть на этот хэш-код. Если нет совпадения, тогда запись, конечно же, не находится в БД; Если есть совпадение, мне все равно придется искать в БД любые дубликаты. Это наверняка будет быстрее, но мне все еще интересно, может ли sqlite сделать это более эффективным.

ответ

1

Вы можете использовать UNIQUE ограничение столбца или объявить несколько столбцов ограничение уникальности вы можете использовать UNIQUE() ON CONFLICT:

CREATE TABLE name (id int , UNIQUE (col_name1 type , col_name2 type) ON CONFLICT IGNORE) 

SQLite имеет два способа выражения ограничения уникальности: PRIMARY KEY и UNIQUE. Оба они создают индекс, и поиск происходит через созданный индекс.

+0

Как насчет производительности?Будет ли он просто искать все элементы отдельно или использовать какой-нибудь более умный (более быстрый) алгоритм, например. как использовать хеш, чтобы ускорить это? –

+0

Также UNIQUE с несколькими столбцами: [Для каждого ограничения UNIQUE в таблице каждая строка должна иметь уникальную комбинацию значений в столбцах, идентифицированных ограничением UNIQUE.] (Http://www.sqlite.org/lang_createtable.html) – danihp

+0

@ThomasTempelmann для поиска это вопрос, если у вас есть указатель на этот столбец, вы можете ускорить поиск наверняка ... – aleroot

2

Try:

sqlite> create table foo (
    ...>   a int, 
    ...>   b int, 
    ...>   unique(a, b) 
    ...>); 
sqlite> 
sqlite> insert into foo values(1, 2); 
sqlite> insert into foo values(2, 1); 
sqlite> insert into foo values(1, 2); 
Error: columns a, b are not unique 
sqlite> 
+0

Хорошо, это объясняет синтаксис. Как насчет производительности? См. Мой комментарий к @aleroot –

+0

@ThomasTempelmann, я не могу помочь с частью производительности, я никогда не использовал sqlite в тяжелом используемом приложении. –

1

Если вы не хотите использовать SQL подход (как указано в других ответах) вы можете сделать выбор для всех ваших данных при запуске программы, хранить данные в словарь и работа со словарем, решить, какие записи нужно вставить в вашу БД.

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

+0

Хотя это не плохая идея, я боюсь, что у меня может не хватить памяти. Следовательно, хранение записей один за другим в базе данных в первую очередь. * Если * я должен использовать хэширующий подход, я мог бы использовать ваше предложение для хранения этих хэшей в локальной памяти при запуске приложения. Если это не слишком сложно, как поиск хэшей так же быстро в БД. –

+0

@ThomasTempelmann - Из моих несвязанных тестов доступ к памяти намного быстрее, чем доступ к БД (пока память не кэшируется на диск). – asafrob

+0

Ну ... то же самое касается и sqlite db. Если двигатель хорошо написан (и я предполагаю, что он есть), он будет использовать файлы ввода-вывода с отображением памяти, позволяя файлу получить доступ как память (которую можно поменять местами и на диск так же, как и в основной памяти приложения). И индекс db - это не что иное, как (отсортированное) двоичное дерево. Что похоже на то, что языки программирования (т. Е. Их библиотеки поддержки) используют для некоторых типов словарей с ключевыми значениями (например, аналогично C++ STL std :: map). Тем не менее, есть некоторые накладные расходы для разбора SQL-команд и т. Д. –

Смежные вопросы