Самый быстрый способ запросить существование объекта в NHibernate - PullRequest
1 голос
/ 03 июня 2009

Я ищу самый быстрый способ проверить наличие объекта . Сценарий довольно прост, предположим, что каталог инструментов, который читает текущий жесткий диск. Когда каталог найден, он должен быть либо создан, либо, если он уже существует, обновлен.

Сначала давайте сосредоточимся только на части создания:

    public static DatabaseDirectory Get(DirectoryInfo dI)
    {
        var result = DatabaseController.Session
                      .CreateCriteria(typeof (DatabaseDirectory))
                      .Add(Restrictions.Eq("FullName", dI.FullName))
                      .List<DatabaseDirectory>().FirstOrDefault();

        if (result == null)
        {
            result = new DatabaseDirectory
                         {
                             CreationTime = dI.CreationTime,
                             Existing = dI.Exists,
                             Extension = dI.Extension,
                             FullName = dI.FullName,
                             LastAccessTime = dI.LastAccessTime,
                             LastWriteTime = dI.LastWriteTime,
                             Name = dI.Name
                         };
        }
        return result;
    }

Это путь к:

  • Скорость
  • Разделение концерна

Что приходит на ум, так это: сканирование всегда будет выполняться «целиком». То есть во время сканирования диска C я знаю, что ничего нового не добавляется в базу данных (из какого-то другого процесса). Так что МОЖЕТ быть хорошей идеей «кэшировать» все существующие каталоги до сканирования и искать их таким образом. С другой стороны, это может не подходить для больших наборов данных, таких как файлы (которых будет 600 000 или более) ...

Возможно, некоторый прирост производительности может быть достигнут с помощью «столбцов индекса» или чего-то подобного, но я не очень знаком с этой темой. Если у кого-то есть ссылки, просто наведите меня в правильном направлении ...

Спасибо, Chris

PS: я использую NHibernate, Fluent Interface, Automapping и SQL Express (может переключиться на полный SQL)

Примечание: В данной проблеме путь не является идентификатором в базе данных. Идентификатор - автоинкремент, и я не могу изменить это требование (другие причины). Таким образом, реальный вопрос заключается в том, что является самым быстрым способом «проверки на существование объекта, где идентификатор неизвестен, просто свойство этого объекта»

И пакетирование может быть возможным, выбрав большую группу с чем-то вроде «начинается с C: Testfiles \», но проблема остается, как я знаю заранее, насколько большим будет этот набор. Я не могу выбрать «макс. 1000» и проверить в этом буферизованном словаре, потому что я могу «нажать рядом с искомым каталогом» ... Я надеюсь, что эта проблема ясна. Наиболее важной частью является то, что буферизация действительно сильно влияет на производительность. Если это так, имеет ли смысл загружать всю БД в словарь, содержащий только PATH и ID (что будет в порядке, даже если есть 1 000 000 объектов, я думаю ..)

1 Ответ

2 голосов
/ 03 июня 2009

Прежде всего, я настоятельно рекомендую вам (любому, кто действительно использует NH) прочитать статью Айенде о различиях между Get, Load и запросом .

В вашем случае, поскольку вам нужно проверить существование, я бы использовал .Get(id) вместо запроса для выбора одного объекта.

Однако мне интересно, могли бы вы улучшить производительность, используя некоторые знания о вашей проблемной области. Если вы собираетесь сканировать весь диск и проверять наличие каждого каталога в базе данных, вы можете повысить производительность, выполняя массовые операции. Возможно, создайте объект DTO, который содержит только PK вашего DatabaseDirectory объекта, чтобы дополнительно минимизировать передачу / обработку данных. Что-то вроде:

Dictionary<string, DirectoryInfo> directories;
session.CreateQuery("select new DatabaseDirectoryDTO(dd.FullName) from DatabaseDirectory dd where dd.FullName in (:ids)")
    .SetParameterList("ids", directories.Keys)
    .List();

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

Что касается разделения интересов, просто сохраните операцию на уровне хранилища. Иметь такой метод, как SyncDirectories, который принимает коллекцию (может быть, Dictionary, если вы выполните что-то подобное выше), который обрабатывает процесс обновления базы данных. Таким образом, ваша высшая логика приложения не должна беспокоиться о том, как все это работает, и не будет затронута, если вы найдете еще более быстрый способ сделать это в будущем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...