Оптимизация 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 возвращает разные значения ошибок для разных сообщений об ошибках.

Другие вопросы по тегам