В настоящее время я оцениваю использование ADO.NET для приложения C++, которое в настоящее время использует старый добрый ADO. Учитывая, что мы полностью переделываем взаимодействие с базой данных, мы хотели бы определить, будет ли полезным использование более современной и активно разрабатываемой технологии ADO.NET.
После некоторых измерений выяснилось, что для некоторых тестовых запросов, которые извлекают много строк с несколькими столбцами, которые все содержат строки, ADO.NET на самом деле для нас примерно на 20% медленнее, чем при использовании простого ADO. Наш профилировщик предполагает, что преобразование результатов System.String в std::wstring, используемое приложением, является одним из узких мест. Я не могу переключить ни один из верхних уровней приложения на использование System.String, поэтому мы застряли на этом конкретном преобразовании.
Грубая схема кода выглядит так:
System::Data::SqlClient::SqlCommand^ sqlCmd =
gcnew System::Data::SqlClient::SqlCommand(cmd, m_DBConnection.get());
System::Data::SqlClient::SqlDataReader^ reader = sqlCmd->ExecuteReader();
if (reader->HasRows)
{
using namespace msclr::interop;
while (reader->Read())
{
std::vector<std::wstring> results;
for (int i=0; i < reader->FieldCount; ++i)
{
std::wstring col_data;
TypeCode type = Type::GetTypeCode(reader->GetFieldType(i));
switch (type)
{
// ... omit lots of different types
case TypeCode::String:
{
System::String^ tmp = reader->GetString(i);
col_data = marshal_as<std::wstring>(tmp);
}
break;
// ... more type conversion code removed
}
results.push_back(col_data);
}
// NOTE: Callback into native result processing code
ResultsCallback(results);
}
Я потратил много времени на изучение различных способов получения std::wstring из System.String и измерил большинство из них. Все они работают примерно одинаково — мы говорим о десятичных точках в процентах использования ЦП. В конце концов, я просто решил использовать marshal_as<std::wstring>, так как он наиболее удобочитаем и кажется таким же эффективным, как и другие решения (например, использование PtrToStringChars или метода, описанного в MSDN здесь).
Использование DataReader очень хорошо работает с концептуальной точки зрения, поскольку большая часть обработки, которую мы выполняем с данными, в любом случае ориентирована на строки.
Единственным другим слегка неожиданным узким местом, которое я заметил, является извлечение TypeCode для столбцов результатов; Я уже планирую перенести это за пределы основного цикла обработки результатов и получать коды типов только один раз для каждого результата запроса.
После этого длинного введения кто-нибудь может порекомендовать менее затратный способ преобразования строковых данных из System.String в std::wstring, или я уже смотрю на оптимальную производительность здесь? Я, очевидно, больше ищу немного необычные способы, учитывая, что я уже пробовал все обычные...
EDIT: похоже, я попал в ловушку, которую сам же и устроил. Да, приведенный выше код примерно на 20 % медленнее, чем эквивалентный простой код ADO в режиме Debug. Однако при переключении в режим Release узкое место по-прежнему можно измерить, но приведенный выше код ADO.NET неожиданно почти на 50 % быстрее, чем старый код ADO. Так что, хотя меня все еще немного беспокоит стоимость преобразования строк, в режиме Release она не так велика, как кажется на первый взгляд.