Как я должен реализовать огромный, но простой индексированный строковый список в Delphi?

75
10

Я использую Delphi 2009. У меня очень простая структура данных с двумя полями:


    Строка, которая является ключевым полем, которое мне нужно получить, и обычно имеет длину от 4 до 15 символов.
    Строка, которая представляет собой поле данных, которое может быть любого размера, от 1 символа до 10 000 символов.

Трудность состоит в том, что у меня может быть несколько миллионов этих записей, поэтому они могут иметь размер не более 10 ГБ. Очевидно, что я ищу решение на диске, а не решение в памяти.


Моя программа должна произвольно извлекать эти записи на основе поля ключа. То, что эта часть должна быть сделана максимально эффективной.


Должен ли я использовать базу данных для такой простой структуры, и если да, то какая база данных лучше всего справиться с этим и будет проще всего реализовать?


В качестве альтернативы существует ли простая структура данных на диске, не требующая полномасштабной базы данных, которая будет работать так же хорошо?


Ну, мне нужен был единственный ответ, чтобы вернуть меня в реальность. Я искал что-то более простое, чем простая база данных. Но когда нет-duh ответ на использование базы данных, я понимаю, что уже ответил на этот вопрос своим собственным ответом на другой вопрос: Лучшая база данных для небольших приложений и инструментов.


Мой ответ был DISQLite3 для причин, которые я указал там. И это то, что я, вероятно, с моей реализацией.


Несколько хороших ответов с некоторыми возможностями. Это здорово. Я смогу попробовать несколько разных методов, чтобы увидеть, что лучше всего работает.


Больше созерцания, и мне пришлось изменить принятый ответ на решение GpStructuredStorage.


В моем случае миллион записей в сумме нескольких гигабайт накладывает нагрузку на структуру базы данных. В частности, дерево B *, которое используется для хранения индекса в большинстве баз данных, выполняется быстро, но замедляется для некоторых операций, таких как переиндексирование миллиона значений.


Единственное, что вы найдете быстрее, чем B * для индекса, - это хеш-таблица. И это именно то, что предусмотрено в gabr, предложенном дополнением к решению GpStructuredStorage. Я думаю, что это довольно элегантно, так как он сегментировал хеш-значение, чтобы создать структуру каталогов на 4 уровня.


Основная причина, по которой я могу перейти к хэш-решению, - это то, что мне нужен только произвольный доступ к ключам. Мне не нужно сортировать по клавишам. Если бы сортировка была необходима, то прибыль от скорости хэш-таблицы была бы потеряна, и система базы данных была бы неразумным победителем.


Когда я приступаю к реализации этого, я должен сделать сравнение этого метода с базой данных. Возможно, я сравню как с Firebird, так и с SQLite, которые оба будут достойными противниками.


Еще одно продолжение:


Я только что обнаружил Синопсис Big Table A. Bouchez, который рассчитан на скорость и точно соответствует спецификациям моего вопроса. Сначала я попробую, когда я сделаю свою реализацию через несколько месяцев и буду сообщать здесь свои результаты.


Значительно позднее последующее наблюдение (июль 2015 г.)


Я никогда не пробовал синопсик Big Table. Я застрял с моим деревом B * до сих пор. Но теперь я обновился до Delphi XE8 и планирую пойти с решением базы данных, используя FireDAC с SQLite.

спросил(а) 2009-11-25T23:07:00+03:00 10 лет назад
7
Решение
45

Синопсис Big Table от A. Буш. См. его ответ на мой другой вопрос о SQLite/DISQLite.

Он даже не был разработан, когда я впервые задал этот вопрос, но теперь он довольно зрелый и полностью функциональный блок.

ответил(а) 2011-07-23T15:45:00+04:00 8 лет, 4 месяца назад
Еще 6 ответов
76

Для данных более 10 ГБ база данных - это именно то, что вам нужно. Он будет обрабатывать индексирование для быстрого поиска данных (ваш случайный поиск), функциональность для добавления, изменения и удаления данных и фактического хранилища, а также многое другое, если вы этого захотите.

Здесь есть десятки сообщений, связанных с тем, какие базы данных доступны для использования в Delphi, включая встроенные и FOS, такие как Firebird.

ответил(а) 2009-11-25T23:11:00+03:00 10 лет назад
70

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


GpStructuredStorage может очень быстро получить имена файлов (я их протестировал), вам нужно сохранить каждую запись в виде файла в GpStructuredStorage и получить каждое имя в виде строки в списке строк, 1 миллионную строку (потому что вы упомянули о stringlist) нуждается в нескольких MB в ОЗУ, что мало, используйте потомок TStream для записи данных в файл в GpStructuredStorage, сегодня у меня нет времени писать простой пример, но в субботу или воскресенье я напишу учебник для GPStructuredStorage в моем блоге.


[Добавлено gabr - Надеюсь, это не будет считаться ужасным нарушением сетевого этикетки. Это просто, что мои мысли не вписываются в комментарий (а именно) и что глупо добавлять другой ответ, просто чтобы написать это...]

В то время как GpStructuredStorage может хранить множество данных, поиск его может быть медленным процессом. То, что я обычно делаю в таких случаях, это создать хэш ключа и преобразовать его в шестнадцатеричный (скажем, 00FFA784). Затем я конвертирую этот шестнадцатеричный хеш в структуру папок (в этом случае он будет /00/FF/A7/84) и сохраняет соответствующие данные в этой папке либо в виде файла, либо в качестве атрибутов, либо в сочетании с ними.


Этот подход ускоряет извлечение данных, но замедляет вставку данных и поэтому рекомендуется только для большинства статических данных. Если данные довольно динамические, я бы рекомендовал использовать базу данных, а не GpStructuredStorage.

ответил(а) 2009-11-26T02:14:00+03:00 10 лет назад
56

Вы должны проанализировать свои данные. Если


    значительная часть значений данных больше, чем размер блока файловой системы по умолчанию,
    вы не хотите искать значения данных с помощью SQL (поэтому неважно, в каком формате они хранятся) и
    вам действительно нужен произвольный доступ к всей базе данных,

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


Но вам нужно измерить, возможно, механизм базы данных сохраняет сжатые данные в любом случае.

ответил(а) 2009-11-26T01:09:00+03:00 10 лет назад
44

Поскольку ваши данные больше 3 ГБ, вам нужно убедиться, что какой-либо механизм базы данных вы выбираете, либо обрабатывает таблицы, большие или разделенные на несколько таблиц, что я предлагаю делать независимо от того, какой максимальный размер одиночный стол. Если вы выполняете разделение, выполните его как можно более равномерным при разрыве логического ключа, чтобы его можно было легко определить, какую таблицу использовать первый или первый два символа ключа. Это значительно сократит время поиска, исключив любые записи, которые никогда не могли соответствовать вашему запросу.


Если вам просто нужна сырая производительность, и вы будете выполнять только просмотр в данных только для чтения, тогда вам будет лучше обслуживаться упорядоченный индексный файл (ы), используя запись фиксированного размера для ваших ключей, которая указывает на ваш файл данных. Затем вы можете легко выполнить бинарный поиск и избегать любых издержек базы данных. Для получения большего увеличения производительности вы можете предварительно загрузить/кешировать средние точки в памяти, чтобы уменьшить повторяющиеся показания.


Простая запись фиксированного размера для ваших спецификаций может выглядеть так:


type
rIndexRec = record
KeyStr : String[15]; // short string 15 chars max
DataLoc : integer; // switch to int64 if your using gpHugeFile
end;

Для начальной загрузки используйте сортировку Turbo Power, найденную в SysTools, которая может быть последней версией для Delphi 2009/2010 загруженный на веб-сайт songbeamers. DataLoc будет позицией потока вашей записи данных, запись или чтение которой может выглядеть следующим образом:


function WriteDataString(aDataString:String;aStream:tStream):integer;
var
aLen : integer;
begin
Result := aStream.Position;
aLen := Length(aDataString);
aStream.Write(aLen,sizeOf(aLen));
aStream.Write(aDataString[1],aLen*sizeOf(Char));
end;

function ReadDataString(aPos:Integer;aStream:tStream):String;
var
aLen : integer;
begin
if aStream.Position <> aPos then
aStream.Seek(aPos,soFromBeginning);
result := '';
aStream.Read(aLen,SizeOf(aLen));
SetLength(Result,aLen);
if aStream.Read(Result[1],aLen*sizeOf(Char)) <> aLen*SizeOf(Char) then
raise Exception.Create('Unable to read entire data string');
end;


Когда вы создаете свои индексные записи, dataloc будет настроен на позицию записи в таблице данных. Не имеет значения порядок загрузки записей, если сортировка записей индекса. Я использовал именно эту технику, чтобы обновить базу данных на 6 миллиардов записей с ежемесячными обновлениями, поэтому она очень легко масштабируется.


ИЗМЕНИТЬ:
Да, приведенный выше код ограничен примерно 2 ГБ на файл данных, но его можно расширить, используя gpHugeFile или сегментирование. Я предпочитаю сегментирование во множество логических файлов < 2gb каждый, что займет немного меньше места на диске.

ответил(а) 2009-11-26T00:48:00+03:00 10 лет назад
44

Если вам больше всего нужны большие наборы данных и у вас есть деньги, просто введите 16GB (500-750 Eur) в машину и сделайте отдельный процесс с помощью своего 64-битного компилятора (*), который вы запрашиваете например, shared mem или другой метод IPC.


В этом случае вы можете использовать подход в памяти до тех пор, пока, наконец, не выйдет 64-битный Delphi. Поскольку ваши данные кажутся простыми (карта из массива char в массив char), ее можно легко экспортировать через IPC.


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


(*) Я рекомендую FPC, конечно: -)


Я сделал это один раз, до 5 миллионов объектов, 5 ГБ данных.


Я получил разрешение на открытие исходных типов контейнеров, которые я сделал для него, они:


http://www.stack.nl/~marcov/lightcontainers.zip (предупреждение: очень грязный код)


mghie: ответить в другом клише: нет серебряной пули


В базах данных также есть много других предположений


    их обобщенный подход делает относительное неэффективное использование памяти. В первую очередь ваш набор данных, использующий обычные методы хранения данных, попадает в доступные диапазоны памяти, которые, конечно, обычно больше для сервера (мое плохое предположение здесь, по умолчанию), чем для клиента.
    Базы данных предполагают, что их результаты могут сводиться к малым наборам в сервере базы данных с относительной прямой обработкой и при помощи индексирования.
    они имеют относительно высокую задержку.
    они относительно плохи в некоторых видах обработки (например, многомерный анализ /OLAP, поэтому для этого необходимо расширить базы данных)

Это делает базы данных относительно плохими для использования, например. кэши, loadbalancers и т.д. Конечно, это все, что вам нужно скорость. Но начальный вопрос был немного чувствителен ко мне.


В прошлом задании моя функция в компании, ориентированной на базу данных, заключалась в том, чтобы делать все, кроме этого, IOW устраняет проблемы, когда стандартный подход не может взломать его (или требуется 4 сокета Oracle-серверов для рабочих мест, где бюджет не оправдал такие расходы). Решение/взлома, написанное выше, было немного OLAPpy и подключено к аппаратным средствам (устройство программирования микропрограммы rfid), требующее определенного гарантированного времени отклика. Два месяца программирования, все еще работает и даже не может купить лицензию на сервер Windows + oracle для стоимости.

ответил(а) 2009-11-26T00:36:00+03:00 10 лет назад
45

BerkleyDB - это именно то, что

ответил(а) 2009-11-25T23:15:00+03:00 10 лет назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема