Оптимизация SQLite для миллионов записей? - PullRequest
4 голосов
/ 27 сентября 2010

Я пытаюсь решить проблему с помощью базы данных SQLite и модулей Perl.В конце концов, я буду регистрировать десятки миллионов записей.Единственный уникальный идентификатор для каждого элемента - это текстовая строка для URL.Я думаю сделать это двумя способами:

Способ № 1: иметь хорошую таблицу, плохую таблицу, несортированную таблицу.(Мне нужно проверить html и решить, хочу ли я его.) Скажем, у нас всего 1 миллиард страниц, 333 миллиона URL в каждой таблице.У меня есть новый URL для добавления, и мне нужно проверить, есть ли он в какой-либо из таблиц, и добавить его в Unsorted, если он уникален.Кроме того, я бы переместил много строк с этой опцией.

Способ №2: у меня есть 2 таблицы, Master и Good.У Master есть все URL-адреса на 1 миллиард страниц, а у Good - 333 миллиона, которые я хочу.Новый URL, нужно сделать то же самое, за исключением того, что на этот раз я запрашиваю только одну таблицу и никогда не удаляю строку из Master, только добавляю данные в Good.

Так что в основном мне нужно знатьлучшая настройка для быстрого запроса огромной базы данных SQLite, чтобы увидеть, является ли текстовая строка ~ 20 символов уникальной, а затем добавить, если это не так.

Редактировать: я сейчас пытаюсьзаставить Беркли БД работать с использованием модуля 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 ]

5 голосов
/ 27 сентября 2010

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

Вот как вы можете использовать гибридный подход хеш / SQLite.

Создать таблицу SQLite

STORE
id INTEGER PRIMARY KEY
BUCKET (integer, indexed) 
URL (text, not indexed)
status 

У вас может быть три из этих таблиц, STORE1, STORE2 и STORE3, если вы хотите хранить их отдельно по статусу.

Предположим, что в каждом магазине будет 250 000 001 отдельных сегментов.(Вы можете поэкспериментировать с этим числом; сделайте его простым числом).

Найдите алгоритм хеширования, который принимает два ввода: строку URL и 250 000 0001 и возвращает число от 1 до 250 000 001.

Когда вы получите URL, передайте его алгоритму хеширования, и он скажет вам, в каком BUCKET искать:

Выберите * из STORE, где BUCKET = {значение, возвращаемое вашей хэш-функцией}.

Ваш индекс в поле BUCKET быстро вернет строки, и вы сможете просмотреть URL-адреса.Если текущий URL не является одним из них, добавьте его:

INSERT STORE(BUCKET, URL) VALUES( {your hash return value}, theURL). 

SQLite будет индексировать целочисленные значения, что, я думаю, будет более эффективным, чем индексирование URL.И URL будет сохранен только один раз.

2 голосов
/ 28 сентября 2010

Если $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.

2 голосов
/ 27 сентября 2010

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

Когда приходит время сделать вставку, база данных принудительно вводит уникальность и выдает какую-то ошибку при попытке вставить дублированный URL.Вы можете перехватить эту ошибку и проигнорировать ее, если DBI возвращает разные значения ошибок для разных сообщений об ошибках.

...