Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Delphi: Для новичков > Контейнер с быстрым поиском по разным полям


Автор: kami 9.6.2013, 21:51
Доброго времени суток, господа!
Есть класс (очень упрощенно):
Код

TmyItem = class(TObject)
public
  property ID: integer; // инвентарный номер, уникальный
  property Name: string; // наименование элемента, уникально
  property ShortName: string; // "общепринятое" наименование, уникально
end;


И контейнер:
Код

 TmyItemContainer = class(TObjectList<TmyItem>)
  public
    property ItemByID[ID: integer]: TmyItem read GetItemByID;
    property ItemByName[Name: string]: TMyItem read GetItemByName;
    property ItemByShortName[ShortName: string]: TMyItem read GetItemByShortName;
  end;


Элементов всего - около 10 тысяч. Часто приходится искать и обрабатывать элементы как по индексу, так и по какому-либо из перечисленных полей, причем - пакетно, по несколько штук.
Поиск по полю выполняется простым перебором. Такого, чтобы искать сразу по нескольким полям - не бывает.
Проблема:
поиск длится долго. AQTime Standart выдает безумные значения в колонке HitCount на TList<TmyItem>.GetItem

Вопрос: как бы это ускорить?
Пока - единственное, что приходит в голову - создать в TItemContainer три "внутренних" TDictionary с ключами по полям ID, Name и ShortName. В Notification TMyItemContainer добавлять/удалять элементы из этих словарей, ну и в функциях GetItemBy... обращаться непосредственно к соответствующему TDictionary...
Не слишком ли я полез в дебри? Может, есть проще способы?

Заранее всем спасибо!

Автор: northener 10.6.2013, 01:46
А использовать БД никак?

Автор: kami 10.6.2013, 08:42
Цитата(northener @  10.6.2013,  01:46 Найти цитируемый пост)
А использовать БД никак?

Тут всплывают дополнительные проблемы smile
я практически не умею работать с БД (простейшие операторы DML не в счет), да и кроме того - обращение на каждый "чих" к БД - затратная операция. Да, изначально все активные элементы считываются из БД (на самом деле их гораздо больше 10к, но активных - примерно столько). Но в дальнейшем это становится слишком накладно. Кроме того - изначальная архитектура приложения (тут уж я бессилен) не терпит кучи открытых датасетов (тем более, что у таблиц куча взаимосвязей 1:много).

Поэтому - можно считать, что никак. smile 

Автор: Illusion Dolphin 11.6.2013, 21:37
Ну тогда делать как БД, т.е. сделать индекс (можно просто по убыванию/возрастанию расположить) по каждому полю и обновлять его по вставке. Поиск - по индексу бинарнм поиском.

Автор: Akella 11.6.2013, 21:55
А зачем куча открытых датасетов?
Может можно 1 или 2?
Я бы тоже рекомендовал БД.
Всё-таки там многое уже реализовано.
Не сегодня, так завтра опять пригодится работа с БД.
Может лучше потратить время на изучение SQL?
На самом деле там всё не так уж и сложно.

Автор: northener 12.6.2013, 01:26
Цитата(kami @  10.6.2013,  08:42 Найти цитируемый пост)
ут всплывают дополнительные проблемы smile
я практически не умею работать с БД

Поверь мне. Это не сложно. Достаточно один раз решиться прыгнуть в воду. smile
А дальше твой опыт и наши советы помогут.
Уже то что ты знаешь про DML говорит о том, что тебе достаточно сделать только ещё один (максимум два) шаг  и ты научишься работать с БД.
Ведь учиться ты умеешь!

Автор: kami 13.6.2013, 14:20
Цитата(northener @  12.6.2013,  01:26 Найти цитируемый пост)
тебе достаточно сделать только ещё один (максимум два) шаг  и ты научишься работать с БД.

Я, наверное, неправильно выразился. Вернее, не наверное, а точно неправильно smile

Моих знаний по SQL (если быть более точным - то по T-SQL и диалекту MySQL) вполне хватает, чтобы создать нужные таблицы/триггеры/ключи/индексы, выдернуть нужные мне данные и занести новые/изменить существующие.

Правильнее будет сказать, что я не умею работать с БД из Delphi.
Как я действую на текущий момент:
1. Общая архитектура - трехзвенка. Клиент - сервер приложений общаются между собой по TCP (собственная многослойная надстройка)
2. Клиент, после авторизации, запрашивает у сервера приложений актуальные данные. Тот запрашивает БД, читает в TmyItems кучу всего и вся и отдает это "всё и вся" клиенту. Сразу после чтения датасеты закрываются, но контейнер остается жить со всем прочитанным.
3. Клиент что-то там меняет, изменения приходят на сервер приложений, записываются в БД и автоматом рассылаются всем подключенным клиентам, которым эти изменения интересны. Причем - отправляются только изменения, полностью данные не перечитываются, датасеты не открываются.

Вся проблема - в этой рассылке изменений. Потому что сервер приложений (каждое подключение - отдельный поток, вообще ничего не знающий о других) действует так: ага, мне пришло изменение TmyItem с вот таким ID. Он у меня есть? Если нет - создаем новый и Assign его. Если есть - то просто Assign. Потом - отправка клиенту.

Пока экземпляров TmyItem было в районе 150 - это (поиск элемента с таким ID/Name/ShortName) было очень быстро, на несколько порядков быстрее, чем обращаться к БД (такие изменения, требующие рассылки, происходят очень часто, тем более что контейнер TmyItems был свой для каждого подключения. Это было признано более оправданным, чем иметь один на всех и тормозить на синхронизации потоков). Но вот я решил оттестироваться на 10тыс. элементов и понял, что система нагрузку не держит. Вообще.

Я понимаю, что это (в глобальном смысле) неправильный подход для работы с базой. А вот как это было бы идеологически верно и политически правильно - не понимаю. Ибо все прочитанные книги и статьи рассказывают (по большому счету) как подключиться к БД, открыть датасет и отобразить его в DBControls. А про идеологию - ни слова.

Резюмируя: менять архитектуру мне никто не позволит, остаются только сортировки и Dictionary. 

Всем спасибо за участие, но если есть какие-либо мысли/ссылки - буду благодарен.

Автор: PointerToNil 17.6.2013, 18:49
TDictionary - куда уж проще-то?
(если кто-то и написал специальный класс как раз под эту задачу, то он его не распространяет, т.к. задача не общая, а специфическая)
разве что знаешь более быстрые реализации хэш-таблиц - тогда используй их

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)