Вы скажете: если захотеть, всегда можно создать себе проблемы. Но здесь случай не такой.
Простой тест!
Создадим широкую таблицу, 100 колонок (типа String). Добавим в неё пустяковый, в общем-то, объем данных - 3000 строк. Пробежимся по всей таблице, и проставим всем ячейкам значение "test".
foreach (DataRow row in table.Rows)
foreach (DataColumn column in table.Columns)
row[column] = "test";
Замерим время выполнения...
00:00:01.7110978
Ого! Нехило, для такой, вроде бы простой операции!? 2 секунды на каких-то жалких 3000 строк!?
И заметьте, никакого извращенного кода. Вполне нормальный код, который мог бы написать любой из нас. Единственная особенность - широкая таблица, много колонок.
Вот и у нас, в одном из совершенно реальных проектов, обнаружилась широкая таблица на 70 колонок. И с ней возникла похожая проблема. Пришлось немало повозиться, чтобы локализовать эту проблему и понять, в чем дело. И еще полчаса на то, чтобы выяснить, как это исправить.
Решение оказалось довольно неожиданным. Оказывается, в случае широких таблиц, быстрее удалить целую строку и добавить новую (фактически пересоздав таблицу), чем заполнять строки стандартным способом.
Давайте проверим.
Для того, чтобы пример был более реалистичным, я забил таблицу случайными целочисленными значениями, и в дальнейшем использовал для тестирования следующий код:
Measure("Standard method", 1, () =>
{
foreach (DataRow row in table.Rows)
foreach (DataColumn column in table.Columns)
{
int value = Convert.ToInt32(row[column]);
if (value > 100)
row[column] = value * 2;
else
row[column] = value * 3;
}
});
Ничего сложного. Если значение больше 100, умножаем его на 2, иначе на 3.
А теперь то же самое, но с пересозданием строк:
Measure("Row recreate method", 1, () =>
{
for (int i = 0; i < tempTable.Rows.Count; i++)
{
List<object> values = new List<object>();
foreach (DataColumn column in tempTable.Columns)
{
int value = Convert.ToInt32(tempTable.Rows[0][column]);
if (value > 100)
values.Add(value * 2);
else
values.Add(value * 3);
}
tempTable.Rows.RemoveAt(0);
tempTable.Rows.Add(values.ToArray());
}
});
Да уж! Выглядит похуже, а уж читается совсем плохо.
Но давайте потестируем производительность этих двух вариантов кода на таблицах различной конфигурации...
100 колонок, 3000 строк:
Standard method => 00:00:02.3351335
Row recreate method => 00:00:00.1030059
10 колонок, 30000 строк:
Standard method => 00:00:00.2970170
Row recreate method => 00:00:00.1980114
1 колонка, 300000 строк:
Standard method => 00:00:00.1740099
Row recreate method => 00:00:01.2810733
Результаты налицо: для большинства таблиц вариант с пересозданием строк будет работать очень быстро.
P. S. Исходники метода Measure можно взять из статьи про производительность Lua Interface.
Комментариев нет:
Отправить комментарий
Внимание! Реклама и прочий спам будут беспощадно удаляться.
Примечание. Отправлять комментарии могут только участники этого блога.