К сожалению, при тестировании средств доступа к базам данных (ADO.Net, ADO, ascDB) в одном из тестов были допущены несколько ошибок. После исправления ошибок оказалось необходимым внести некоторые корректировки в результаты тестирования, приведенные в предыдущей статье. Я приношу читателям свои извинения, каюсь и надеюсь, что подобного более не повторится.
Кроме упомянутых выше, есть и ещё одна причина, из-за которой я возвращаюсь к старой теме. Дело в том, что разработчикам удалось существенно ускорить ascDB в самом узком месте, а именно снизить время сохранения данных после их изменения примерно в полтора раза.
К сожалению, повторить старые условия тестирования не представилось возможным, поскольку изменились конфигурации машин, участвующих в тесте (в том числе изменились операционные системы, установленные на них).
Естественно, что, учитывая ошибки и изменение конфигурации, бессмысленно сравнивать новые данные со старыми. Однако, все описания тестов и выводы, сделанные в предыдущей статье, остаются в силе, за исключением изменений, описанных ниже. Так уж получилось, что результаты неверных тестов оказались недалеки от истины. :)
Где же были допущены ошибки и как они сказались на результатах тестирования? Все ошибки, коварно маскируясь во мраке кода, закрались в тест ChangeData.
Первая, самая непростительная и существенная из ошибок, "поразила" область выполнения операции Update, бесчестно сведя к минимуму количество реально выполняемых изменений данных в строках курсора. В коде теста после каждого вызова метода CursorUpdate находился лишний, вероятно, забытый в результате многочисленных правок, вызов метода CursorFetchRandom. Ниже приведен фрагмент кода с ошибкой (переменная curs представляет собой ascVisualCursor (ascDB), Recordset (ADO) или DataSet (ADO.Net)):
For j = 1 To 10 CursorUpdate curs CursorFetchRandom curs, iPosition30 Next |
Понятно, что в этом случае на клиенте выполнялось 10 модификаций одной и той же строки, но на сервере операция Update выполнялась только один раз для одной строки вместо изменения значений в десяти строках. Правильный код выглядит так:
For j = 1 To 10 CursorUpdate curs CursorFetchNext curs Next |
Исправление этой ошибки привело к изменению результатов теста ChangeData. Это произошло за счёт увеличения времени записи изменений для всех тестируемых средств доступа к базам данных.
Вторая ошибка заключалась в том, что в тесте ChangeData для ADO в методах CursorInsert, CursorDelete и CursorUpdate при нахождении курсора в состоянии EOF вызывался метод MovePrevious объекта Recordset. Это могло привести к значительным потерям времени в случае, когда курсор не был отключен от базы данных (из-за крайне медленной работы навигации по курсору ADO в connected-режиме).
Реорганизация теста позволила избежать ситуации EOF, в результате чего время выполнения операций Update и Delete в тесте ADO (connected-режим) очень сильно сократилось. Про операцию Insert сказано ниже (в описании третьей ошибки).
Третья и, надеюсь, последняя ошибка относилась только к методу CursorInsert теста ChangeData для ADO. Случайным и невероятным образом из кода этого метода исчезла крайне необходимая строка «ars.AddNew» (в которой ars является объектом Recordset), что неизбежно привело в полному отсутствию реальных вставок строк в тесте.
После добавления исчезнувшей строки время выполнения операции Insert (в тесте ChangeData для ADO), разумеется, возросло.
Изменения в тесте Forward коснулись только ADO.NET.
В результате внимательного рассмотрения проблемы больших затрат времени на выполнение метода Close объектов SqlDataReader и OleDbDataReader оказалось, что при попытке закрыть Reader выполняется докачка всех еще не считанных записей. Чтобы избежать этой неприятности при переоткрытии объекта в случае циклического повторения теста, были внесены изменения в код метода CloseReader тестового приложения. В старом коде выполнялось простое закрытие объекта SqlDataReader:
m_sdrReader.Close(); |
В новом коде дополнительно вызывается метод Cancel команды (объекта SqlCommand или OleDbCommand, в зависимости от определения #define CompileWithSqlClient или CompileWithOleDb):
m_cmd.Cancel(); m_sdrReader.Close(); |
После вызова метода Cancel команды, Reader закрывается намного быстрее. Однако появились проблемы. Иногда после этой операции в SQL-сервере появлялись блокировки, которые приводили к зависанию теста (с выдачей таймаута).
Анализируя новые результаты тестов, необходимо учитывать, что, помимо исправления ошибок, произошли следующие изменения.
В качестве клиентской машины во всех случаях использовался компьютер со следующими параметрами:
В качестве серверной машины в случае удаленных тестов использовался компьютер со следующими параметрами:
Тестовые приложения и библиотеки ADO.NET скомпилированы на C# из поставки Microsoft Development Environment 2003 Beta (Version 7.1.2292), Microsoft .Net Framework 1.1 (Version 1.1.4322).
Сам тест ChangeData был несколько реорганизован (увеличилось количество вызовов метода CursorFetch), увеличилось и количество вызовов методов CursorInsert и CursorUpdate.
Также нельзя забывать, что скорость записи изменений в курсоре ascDB была существенно увеличена разработчиками. Поэтому, несмотря на увеличение количества измененных строк, произошедшее в результате исправления ошибок, время записи изменений в ascDB сократилось почти вдвое. Дальнейшее ускорение работы ascDB представляется маловероятным по той причине, что ascDB поддерживает механизм триггеров, который в текущей версии невозможно отключить. Данные перед любой модификацией извлекаются из БД и передаются в триггерные события. К тому же модификация данных производится с помощью курсоров, что на некоторых СУБД дает дополнительные задержки.
Ниже приведены новые результаты тестов.
ChangeData (10 итераций) | Insert | Update | Delete | Fetch | Save | Reopen |
---|---|---|---|---|---|---|
Количество повторов операции | 1150 | 1100 | 1150 | 3930 | 10 | 10 |
ChangeData (10 итераций) | InProcess Client | COM+ Client | Net RemotingClient | COM+ Server | Net Remoting Server |
---|---|---|---|---|---|
ADO.NET | 21.17 | 250.24 | 267.775 | 205.957 | 194.74 |
ADO (в скобках – disconnected) | 39.156 (13.539) | 17.715 | нет | 33.808 | нет |
AscDB | 17.055 | 18.177 | нет | 32.046 | нет |
Как видно по таблице, общее время выполнения теста ADO.NET в удаленном режиме значительно меньше, чем время выполнения того же теста в соответствующих локальных режимах. Вероятнее всего, это связано с использованием в качестве клиента более быстрой машины с большим объемом оперативной памяти. В результате разница в скорости копирования данных при их десериализации на клиенте оказалась существенной, и даже передача данных по сети не смогла сгладить разницу. Подробнее о причинах медленной сериализации объекта DataSet было сказано в предыдущей статье. Единственное, что можно добавить – похоже, DataSet всегда сериализуется в XML. Однако вряд ли этим фактом можно объяснить столь медленную сериализацию.
ChangeData (10 итераций) | Insert | Update | Delete | Fetch | Save | Reopen | Всего |
---|---|---|---|---|---|---|---|
ADO.NET | 0.020 | 0.070 | 0.00 | 0.030 | 14.129 | 6.921 | 21.170 |
ADO (connected) | 0.310 | 0.170 | 0.02 | 29.942 | 7.030 | 1.674 | 39.156 |
ADO (disconnected) | 0.361 | 0.481 | 0.07 | 0.601 | 7.209 | 4.817 | 13.539 |
ascDB | 0.461 | 0.601 | 0.01 | 2.053 | 10.685 | 3.245 | 17.055 |
ChangeData (10 итераций) | Insert | Update | Delete | Fetch | Save | Reopen | Всего |
---|---|---|---|---|---|---|---|
ADO.NET | 0.08 | 0.152 | 0.02 | 0.020 | 21.682 | 228.286 | 250.240 |
ADO | 0.36 | 0.451 | 0.08 | 0.641 | 5.458 | 10.725 | 17.715 |
ascDB | 0.48 | 0.471 | 0.02 | 2.845 | 10.965 | 3.396 | 18.177 |
ChangeData (10 итераций) | Insert | Update | Delete | Fetch | Save | Reopen | Всего |
---|---|---|---|---|---|---|---|
ADO.NET | 0.04 | 0.04 | 0.01 | 0.000 | 26.11 | 179.757 | 205.957 |
ADO | 0.11 | 0.17 | 0.00 | 0.270 | 6.510 | 26.748 | 33.808 |
ascDB | 0.653 | 0.17 | 0.01 | 15.479 | 11.708 | 4.026 | 32.046 |
Преимущество ADO (disconnected-режим) над ascDB теперь представляется незначительным. Хотя нельзя забывать о том, что в disconnected-режиме ADO вынуждено передавать весь курсор на клиента, а ascDB – нет. Дело в том, что ascDB реализует полноценную докачку (поблочную) данных, что можно сравнить с обычным connected-режимом ADO. Однако, во-первых, в обычном режиме ADO показало намного худшие результаты, а во-вторых, disconnected-режим – единственный разумный режим для ADO, так как подключенный курсор в ADO передается по ссылке, и любой вызов метода будет осуществляться по сети.
Неверным оказался вывод о низкой скорости выполнения операции Delete в ADO (connected-режим): в этом режиме тормозит только операция Fetch (т.е. Move метода Recordset).
Подтвердилось, что увеличение объема оперативной памяти сверх 256 Мб существенно ускоряет работу ADO.NET, тогда как для ADO и ascDB вполне достаточно 256 Мб (разумеется, речь идет о тесте ChangeData, так как остальные тесты не изменялись).
Прочие выводы остались без изменений.
Я ещё раз приношу читателям искренние извинения за допущенные ошибки.
Возможно, памятуя о непростительности ошибок в подобных тестах, автору следовало бы совершить ритуальное самоубийство, но надеюсь, что отсутствие среди предков автора самураев позволяет мне сохранить себе жизнь и рассчитывать в дальнейшем на прощение читательской аудиторией :-).