Список производительности SqlDataReaderили список - PullRequest
7 голосов
/ 07 ноября 2011

Я экспериментировал со способами чтения данных с сервера SQL как можно быстрее, и я наткнулся на интересное открытие. Если я читаю данные в List<object[]> вместо List<string[]>, производительность увеличивается более чем вдвое.

Я подозреваю, что это связано с тем, что нет необходимости вызывать метод ToString() для полей, но я всегда думал, что использование объектов отрицательно влияет на производительность.

Есть ли причина не использовать список массивов объектов вместо строковых массивов?

РЕДАКТИРОВАТЬ: Одна мысль, которую я только что имел, был размер хранения этих данных. Сохранение данных в массивах объектов займет больше места, чем в виде строк?

Вот мой тестовый код:

private void executeSqlObject()
    {
        List<object[]> list = new List<object[]>();

        using (SqlConnection cnn = new SqlConnection(_cnnString))
        {
            cnn.Open();
            SqlCommand cmd = new SqlCommand("select * from test_table", cnn);

            SqlDataReader reader = cmd.ExecuteReader();

            int fieldCount = reader.FieldCount;

            while (reader.Read())
            {
                object[] row = new object[fieldCount];

                for (int i = 0; i < fieldCount; i++)
                {
                    row[i] = reader[i];
                }
                list.Add(row);
            }
        }
    }

    private void executeSqlString()
    {
        List<string[]> list = new List<string[]>();

        using (SqlConnection cnn = new SqlConnection(_cnnString))
        {
            cnn.Open();
            SqlCommand cmd = new SqlCommand("select * from test_table", cnn);

            SqlDataReader reader = cmd.ExecuteReader();

            int fieldCount = reader.FieldCount;

            while (reader.Read())
            {
                string[] row = new string[fieldCount];

                for (int i = 0; i < fieldCount; i++)
                {
                    row[i] = reader[i].ToString();
                }
                list.Add(row);
            }
        }
    }

    private void runTests()
    {
        Stopwatch watch = new Stopwatch();
        for (int i = 0; i < 10; i++)
        {
            watch.Start();
            executeSqlObject();
            Debug.WriteLine("Object Time: " + watch.ElapsedMilliseconds.ToString());
            watch.Reset();
        }
        for (int i = 0; i < 10; i++)
        {
            watch.Start();
            executeSqlString();
            Debug.WriteLine("String Time: " + watch.ElapsedMilliseconds.ToString());
            watch.Reset();
        }
    }

И результаты:

Object Time: 879
Object Time: 812
Object Time: 825
Object Time: 882
Object Time: 880
Object Time: 905
Object Time: 815
Object Time: 799
Object Time: 823
Object Time: 817
Average: 844

String Time: 1819
String Time: 1790
String Time: 1787
String Time: 1856
String Time: 1795
String Time: 1731
String Time: 1792
String Time: 1799
String Time: 1762
String Time: 1869
Average: 1800

Ответы [ 2 ]

8 голосов
/ 07 ноября 2011

object только добавляет накладные расходы, если вы вызываете дополнительный бокс. И даже тогда это влияние довольно минимально. В вашем случае reader[i] всегда возвращает object. У вас уже есть это как object, независимо от того, является ли это ссылкой на строку, или int, и т. Д. Из course вызов .ToString() добавляет накладные расходы; в большинстве случаев (int, DateTime и т. д.) это включает как форматирование кода , так и выделение одной (или более) дополнительной строки. Изменяя на string, вы изменяете данные (в худшем случае, IMO, например, вы больше не можете делать правильные сортировки по датам, например) и добавляете накладные расходы. Крайний случай здесь, если все столбцы уже являются строками - в этом случае вы просто добавляете несколько вызовов виртуальных методов (но без дополнительной реальной работы).

Для информации, если вам не хватает сырой производительности, я настоятельно рекомендую взглянуть на микро-ORM, такие как dapper. Они сильно оптимизированы, но избегают веса "полных" ORM. Например, в dapper:

var myData = connection.Query<TypedObject>("select * from test_table").ToList();
Я ожидаю, что

будет работать очень сравнимо, предоставляя вам строго типизированные данные объекта.

1 голос
/ 07 ноября 2011

Есть ли причина не использовать список массивов объектов вместо строковых массивов?

Это будет зависеть от того, что вы хотите сделать с полученными значениями после того, как вы поместили их в массивы. Если вы будете счастливы рассматривать каждое значение как объект, тогда наличие списка объектов - это хорошо, но если вы хотите относитесь к ним как к строкам, и в какой-то момент вам придется преобразовать / привести объект обратно к строке, чтобы вы где-то понесли расходы.

Как отметил Кори, если вы читаете значение в виде строки из SqlDataReader, вам следует протестировать, используя метод GetString (int), а не вызывать ToString () для значения, и использовать его в качестве эталона.

В качестве альтернативы, вместо использования массивов вы можете считывать значения в DataSet, с которым впоследствии может оказаться проще работать.

Конец дня, то, что лучше, во многом зависит от того, как вы хотите использовать результаты после извлечения их из базы данных.

...