Оптимизация SQLite для миллионов записей?
Я пытаюсь решить проблему с помощью базы данных SQLite и модулей Perl. В конце концов, я буду регистрировать десятки миллионов записей. Единственный уникальный идентификатор для каждого элемента - это текстовая строка для URL. Я думаю сделать это двумя способами:
Способ № 1: Иметь хороший стол, плохой стол, несортированный стол. (Мне нужно проверить html и решить, хочу ли я его.) Скажем, у нас всего 1 миллиард страниц, 333 миллиона URL в каждой таблице. У меня есть новый URL для добавления, и мне нужно проверить, есть ли он в какой-либо из таблиц, и добавить его в Unsorted, если он уникален. Кроме того, я бы переместил много строк с этой опцией.
Способ № 2: У меня есть 2 стола, Мастер и Гуд. У Master есть все 1 миллиард страниц URL, а у Good - 333 миллиона, которые я хочу. Новый URL, нужно сделать то же самое, за исключением того, что на этот раз я запрашиваю только одну таблицу и никогда не удаляю строку из Master, только добавляю данные в Good.
В общем, мне нужно знать лучшую настройку для быстрого запроса огромной базы данных SQLite, чтобы увидеть, является ли текстовая строка из ~20 символов уникальной, а затем добавить, если это не так.
Изменить: я сейчас пытаюсь заставить Беркли DB работать с использованием модуля Perl, но не игра в кости. Вот что у меня есть:
use BerkeleyDB;
$dbFolder = 'C:\somedirectory';
my $env = BerkeleyDB::Env->new ( -Home => $dbFolder );
my $db = BerkeleyDB::Hash->new (
-Filename => "fred.db",
-Env => $env );
my $status = $db->db_put("apple", "red");
И когда я запускаю это, я получаю следующее:
Can't call method "db_put" on an undefined value at C:\Directory\perlfile.pl line 42, <STDIN> line 1.
3 ответа
Если $db
не определено, открытие базы данных не удается, и вы должны проверить $!
а также $BerkeleyDB::Error
чтобы понять почему.
Вы уже создали базу данных? Если нет, вам нужно -Flags => DB_CREATE
,
Рабочий пример:
use strict;
use warnings;
use BerkeleyDB;
my $dbFolder = '/home/ysth/bdbtmp/';
my $db = BerkeleyDB::Hash->new (
-Filename => "$dbFolder/fred.db",
-Flags => DB_CREATE,
) or die "couldn't create: $!, $BerkeleyDB::Error.\n";
my $status = $db->db_put("apple", "red");
Я не мог заставить BerkeleyDB::Env сделать что-нибудь полезное; что бы я ни пытался, конструктор вернул undef.
Я был бы склонен использовать хеш вместо SQLite, чтобы делать то, что вы хотите. Хэш оптимизирован для проверки существования без необходимости сохранять значения в каком-либо отсортированном порядке и без необходимости сохранять избыточную копию данных в индексе. Алгоритм хеширования, примененный к данным, дает место, где он будет храниться, если он существует; Вы можете искать это место и посмотреть, есть ли оно там. Я не думаю, что вам нужно хранить хэш-таблицу в оперативной памяти.
Вот как вы можете использовать гибридный подход хеш /SQLite.
Создать таблицу SQLite
STORE
id INTEGER PRIMARY KEY
BUCKET (integer, indexed)
URL (text, not indexed)
status
У вас может быть три из этих таблиц, STORE1, STORE2 и STORE3, если вы хотите сохранить их отдельно по статусу.
Предположим, что в каждом магазине будет 250 000001 разных ведер. (Вы можете поэкспериментировать с этим числом; сделайте его простым числом).
Найдите алгоритм хеширования, который принимает два ввода: строку URL-адреса и 250 000 0001 и возвращает число от 1 до 250 000001.
Когда вы получите URL, передайте его алгоритму хеширования, и он скажет вам, в каком BUCKET искать:
Выберите * из STORE, где BUCKET = {значение, возвращаемое вашей хэш-функцией}.
Ваш индекс в поле BUCKET быстро вернет строки, и вы сможете просмотреть URL-адреса. Если текущий URL не является одним из них, добавьте его:
INSERT STORE(BUCKET, URL) VALUES( {your hash return value}, theURL).
SQLite будет индексировать целочисленные значения, что, я думаю, будет более эффективным, чем индексирование URL. И URL будет сохранен только один раз.
Я не знаю, является ли это оптимальным, но вы могли бы настроить свою базу данных SQLite таким образом, чтобы "хорошая" таблица имела уникальное ограничение на столбец URL. Возможно, у вас недостаточно оперативной памяти для сравнения в Perl (наивным решением было бы создать хеш, где URL-адреса являются ключами, но если у вас есть миллиард страниц, вам понадобится очень много памяти).
Когда приходит время для вставки, база данных обеспечивает уникальность и выдает какую-то ошибку, когда пытается вставить дублированный URL. Вы можете перехватить эту ошибку и проигнорировать ее, если DBI возвращает разные значения ошибок для разных сообщений об ошибках.