Фиксация ОЧЕНЬ медленная в моем проекте NHibernate / SQLite - PullRequest
3 голосов
/ 26 марта 2010

Я только начал проводить некоторые тесты производительности моего проекта Fluent NHibernate / SQLite и испытываю серьезные задержки при фиксации базы данных. Серьезно, я имею в виду 20-30 секунд, чтобы зафиксировать 30 КБ данных!

Эта задержка, похоже, ухудшается по мере роста базы данных. Когда файл БД SQLite пуст, коммиты происходят почти мгновенно, но когда он увеличивается до 10 мегабайт, я вижу эти огромные задержки.

База данных содержит 16 таблиц, в среднем по 10 столбцов каждая.

Одной из возможных проблем является то, что я храню дюжину или около того IList<float> членов, но обычно они состоят всего из 200 элементов. Но это недавнее добавление к автоматическому сопоставлению Fluent NHibernate, в котором каждое число с плавающей точкой хранится в одной строке таблицы, так что, возможно, это потенциальная проблема.

Любые предложения о том, как отследить это? Я подозреваю, что SQLite является виновником, но, может быть, это NHibernate?

У меня нет опыта работы с профилировщиками, но я думаю получить его. Мне известно о NHibernate Profiler - есть ли рекомендации для профилировщиков, которые хорошо работают с SQLite?

Редактировать

Некоторое дополнительное тестирование показывает, что замедление вызывает не размер базы данных - это зависит от того, сколько сохранений я сделал с момента запуска моей программы. Время фиксации для первого сохранения составляет около 300 мс, а к 50-му сохранению составляет более 1000 мс.

Я все время держу одну открытую сессию - может, мне нужна какая-то явная логика Flush?

Кроме того, я скачал NHibernate Profiler. Это дало мне предупреждение о «большом количестве отдельных записей» для моих участников IList. В описании оповещения предлагалось включить пакетную обработку, но, насколько я могу судить, SQLite не поддерживает это.

Также упоминается поддержка Multiquery, поэтому я собираюсь прочитать об этом.

/ Edit

Вот метод, который сохраняет данные - это просто вызов SaveOrUpdate и Commit, если вы игнорируете всю обработку ошибок и ведение журнала отладки.

    public static void SaveMeasurement(object measurement)
    {
        // Get the application's database session
        var session = GetSession();
        using (var transaction = session.BeginTransaction())
        {
            session.Save(measurement);
            transaction.Commit();
        }
    }

Ответы [ 6 ]

4 голосов
/ 27 марта 2010

Ваша транзакция должна охватывать всю операцию, а не каждую операцию.

Вы также выиграете от включения пакетной обработки ado.net: 1000

3 голосов
/ 31 марта 2010

Я думаю, что использование session.evict () охватывает только симптомы. Вы не опубликовали метод GetSession () -, но приведенный выше комментарий и замечание о том, что session.clear () прерывает ленивую загрузку, заставляет меня догадаться, что вы используете один сеанс для всего приложения.
Это крайне неэффективно и замедлит работу вашего приложения. С другой стороны, создание нового сеанса действительно дешево и обеспечит вам чистый и быстрый сеанс, обрабатывающий только те объекты, которые вы хотите.
ИМО вам стоит подумать об декларативном управлении транзакциями. Лично я предпочитаю Springs -TX-Management, но есть и другие умные решения, не основанные на методах, как, например, замок ActiveRecord .

2 голосов
/ 27 марта 2010

Вы говорите, что у вас есть Список объектов измерений, но вы сохраняете их по одному за раз. Это было бы хорошо, если бы все сохранения были в одной транзакции, но каждое сохранение было заключено в транзакцию. Это ухудшит вашу производительность независимо от размера БД.

1 голос
/ 31 марта 2010

Nhibernate никогда не будет быстрым.

Некоторые старые версии nhibernate агрессивно закрывают сеанс с базой данных. Это заставляет его открывать / закрывать базу данных sqlite LOT (что очень медленно). Я полагаю, что в более новых версиях есть опция, позволяющая держать сеанс nhibernate дольше открытым. Если вы используете базу данных памяти, это приводит к потере всего, как только оно закрывается.

Проблема с использованием SQLite: память: с NHibernate

1 голос
/ 27 марта 2010

Используете ли вы первичные ключи автоинкремента? Это заставит NHibernate выполнять выбор после каждой вставки, чтобы заполнить свойство первичного ключа объекта. Я не уверен, как он это делает для SQLite, но ваше утверждение, что проблема усугубляется по мере роста базы данных, указывает на это как на возможную основную причину.

Ваш план использования профилировщика - лучший способ действий. NHibernate Profiler превосходен и имеет пробный период, который позволит вам использовать его для устранения этой проблемы.

0 голосов
/ 31 марта 2010

Редактировать Прочитав ответ Зойдбека, я отказался от этого подхода. Смотрите мой комментарий к его ответу. / Edit

После некоторого поиска в Google я наткнулся на несколько сообщений, в которых подразумевалось, что кеш NHibernate может на самом деле значительно замедлять работу при определенных обстоятельствах. Очевидно, что NH может тратить больше времени на поиск вещей в кэше, чем на фактическую фиксацию.

Я пытался сделать сеанс. Очистить после каждого коммита, но это прервало ленивую загрузку.

Решением (на данный момент) было позвонить:

session.Evict(measurement);

после каждого коммита, который удаляет измерение из кэша. Теперь мои коммиты занимают примерно одинаковое время (около 800 мс для 30 КБ данных), независимо от размера БД.

Кажется, коренной проблемой являются мои IList<float> члены, которые генерируют сотни вставок SQL. Пакетирование, вероятно, решит эту проблему, но, увы, поддерживается только SQL Server, а не SQLite.

В какой-то момент мне придется оптимизировать это - возможно, храня их как BLOB. Но это вопрос к другому дню.

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