Есть ли что-нибудь быстрее, чем SqlDataReader в .NET?

Мне нужно загрузить один столбец строк из таблицы на SqlServer в массив в памяти с помощью С#. Есть ли более быстрый способ, чем открыть SqlDataReader и пройти через него. Таблица большая и время критично.

РЕДАКТИРОВАТЬ Я пытаюсь создать .dll и использовать его на сервере для некоторых операций с базой данных. Но это пока медленно. Если это быстрее, чем мне придется перепроектировать базу данных. Я думаю, может быть какое-то решение, как ускорить процесс.


person watbywbarif    schedule 16.09.2010    source источник


Ответы (11)


Считыватель данных

Самый быстрый доступ к SQL вы получите с SqlDataReader.

Профиль

На самом деле стоит профилировать, где ваша проблема с производительностью. Обычно, когда вы думаете, что проблема с производительностью, оказывается совершенно неправильной после того, как вы ее профилируете.

Например, это может быть:

  1. Время... которое требуется для выполнения запроса
  2. Время... данные тратятся на копирование через границу сети/процесса.
  3. Время... .Net требуется для загрузки данных в память
  4. Время, которое требуется вашему коду, чтобы что-то с ним сделать.

Профилирование каждого из них по отдельности даст вам лучшее представление о том, где находится узкое место. Для профилирования вашего кода есть отличная статья от Microsoft

Кэшировать

Чтобы повысить производительность, нужно обратить внимание на то, если вам нужно каждый раз загружать все эти данные. Можно ли кэшировать список (или его часть)? Взгляните на новую System.Runtime. Кэширование пространства имен.

Переписать как T-SQL

Если вы выполняете исключительно операции с данными (как предполагает ваш вопрос), вы можете переписать свой код, который использует данные, чтобы быть T-SQL и работать изначально на SQL. Это может быть намного быстрее, так как вы будете работать с данными напрямую, а не перемещать их.

Если в вашем коде много необходимой процедурной логики, вы можете попробовать смешать T-SQL с Интеграция с CLR дает вам преимущества обоих миров.

Это во многом сводится к сложности (или более процедурному характеру) вашей логики.

Если ничего не помогает

Если все области оптимальны (или близки к ним), а ваш дизайн безупречен. Я бы даже не стал заниматься микрооптимизацией, я бы просто добавьте к этому оборудование.

Какое оборудование? Воспользуйтесь монитором надежности и производительности, чтобы узнать, где горлышко бутылки есть. Наиболее вероятное место описанной вами проблемы HDD или RAM.

person badbod99    schedule 16.09.2010
comment
Я кое-что проверил, SqlDataReader явно быстрее, чем DataSet ;) Да, время загрузки хуже всего сказывается на производительности. - person watbywbarif; 16.09.2010
comment
И я не отправляю клиенту, .dll используется на той же машине, что и сервер, для некоторого внутреннего использования. - person watbywbarif; 16.09.2010
comment
+1 за переписывание как T-SQL. Идеальный запрос — это тот, который извлекает только абсолютно необходимые данные. Если вы извлекаете 100 тыс. строк в клиентское приложение, а затем обрабатываете их там, возможно, вам следует пересмотреть свою логику. - person BradC; 16.09.2010
comment
Бросание оборудования на это действительно не помогает. SqlClient использует внутренний буфер в зависимости от размера пакета. Самый большой размер пакета составляет 32768 байт, и это БУДЕТ влиять на пропускную способность. Никакое вменяемое количество железа вам там не поможет. - person Jörgen Sigvardsson; 06.02.2020
comment
@JörgenSigvardsson - Это предполагает, что ваша проблема с производительностью связана со скоростью сети и объемом данных. Может быть, но есть много других мест, которые я бы посмотрел в первую очередь. - person badbod99; 25.02.2020

Если SqlDataReader недостаточно быстр, возможно, вам следует хранить свои данные в другом месте, например в кеше (в памяти).

person Steven    schedule 16.09.2010
comment
Согласен - можете ли вы загрузить данные заранее и выполнить итерацию из коллекции в памяти? - person tomfanning; 16.09.2010

Нет. На самом деле это не только самый быстрый способ - это ЕДИНСТВЕННЫЙ (!) способ. Все остальные механизмы ВНУТРЕННЕ в любом случае используют DataReader.

person TomTom    schedule 16.09.2010

Я подозреваю, что SqlDataReader почти так же хорош, как и вы.

person LukeH    schedule 16.09.2010
comment
Ха! Не хотел бы кто-нибудь из противников уточнить, что не так с этим ответом? - person LukeH; 16.09.2010

SqlDataReader — самый быстрый способ. Убедитесь, что вы используете методы получения по порядковому номеру, а не по имени столбца. например ПолучитьСтроку(1);

Также стоит поэкспериментировать с MinPoolSize в строке подключения, чтобы в пуле всегда были какие-то подключения.

person softveda    schedule 16.09.2010
comment
Можете ли вы рассказать больше о MinPoolSize, я не понимаю, как это должно помочь? - person watbywbarif; 16.09.2010
comment
В .Net соединения БД возвращаются в пул соединений после закрытия, а затем в конечном итоге базовое соединение SQL-сервера закрывается после периода бездействия. Это генерирует события входа и выхода. В некоторых сценариях (нечастые вызовы веб-службы) может быть полезно всегда иметь несколько готовых соединений в пуле для быстрой обработки первого запроса, а не открывать новое соединение с SQL-сервером. - person softveda; 17.09.2010

SqlDataReader будет самым быстрым способом. Оптимизируйте его использование, используя соответствующий метод Getxxx, который принимает порядковый номер в качестве параметра.

Если это недостаточно быстро, посмотрите, можете ли вы настроить свой запрос. Поместите покрывающий индекс в столбцы, которые вы хотите получить. Таким образом, Sql Server должен только прочитать индекс, и ему не нужно напрямую обращаться к таблице, чтобы получить всю необходимую информацию.

person Frederik Gheysels    schedule 16.09.2010
comment
Запрос - это выбор только одного столбца, там нет места для оптимизации, только для редизайна базы данных ;( - person watbywbarif; 16.09.2010
comment
@watbywbarif индекс все равно поможет даже при выборе одного столбца - person msarchet; 16.09.2010
comment
Вы создали индекс, который содержит ТОЛЬКО один столбец, который вы выбираете? - person Ian Ringrose; 17.09.2010

Как насчет преобразования одного столбца строк в один ряд столбцов и чтения только одной строки? SqlDataReader имеет оптимизацию для чтения одной строки (System.Data.CommandBehavior.SingleRow аргумент ExecuteReader), поэтому, возможно, это может немного повысить скорость.

Я вижу несколько преимуществ:

  • Однорядное улучшение,
  • Нет необходимости обращаться к массиву на каждой итерации (reader[0]),
  • Клонирование массива (reader) в другой может быть быстрее, чем перебор элементов и добавление каждого из них в новый массив.

С другой стороны, у него есть недостаток — заставить базу данных SQL выполнять больше работы.

person Arseni Mourzenko    schedule 16.09.2010
comment
Звучит странно, но поскольку эта .dll используется на сервере, кажется, что я получаю данные быстрее с помощью SqlDataReader, чем путем построения одной строки в SQL. - person watbywbarif; 16.09.2010

«Предоставляет способ чтения прямого потока строк из базы данных SQL Server». Это использование SqlDataReader из MSDN. Структура данных за SqlDataReder допускает только прямое чтение, она оптимизирована для чтения данных в одном направлении. На мой взгляд, я хочу использовать SqlDataReader, а не DataSet для простого чтения данных.

person coolkid    schedule 16.09.2010

У вас есть 4 набора накладных расходов — доступ к диску — код .net (процессор) — код сервера SQL (процессор) — время переключения между управляемым и неуправляемым кодом (процессор)

Во-первых, это

select * where column = “junk” 

достаточно быстро для вас, если не единственное решение, чтобы сделать диск быстрее. (Вы можете получить данные из SQL Server быстрее, чем он сможет их прочитать)

Возможно, вы сможете определить функцию Sql Server на С#, а затем запустить функцию по столбцу; жаль не знаю как это сделать. Это может быть быстрее, чем считыватель данных.

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

Вы можете написать некоторый TSQL, который объединяет все строки в одну строку, используя разделитель, который, как вы знаете, безопасен. Затем снова разделите строку на С#. Это уменьшит количество циклов обмена между управляемым и неуправляемым кодом.

person Ian Ringrose    schedule 16.09.2010
comment
Я не знаю, как большее количество потоков ускорит загрузку данных, поскольку SqlDataReader читает последовательно? - person watbywbarif; 17.09.2010
comment
Каждый поток может использовать свой собственный SqlDataReader, если вы можете что-то сделать, чтобы определить данные между потоками. - person Ian Ringrose; 17.09.2010
comment
Хорошая идея, может поможет. +1 - person watbywbarif; 30.09.2010

Некоторые вещи поверхностного уровня, которые могут повлиять на скорость (кроме чтения данных):

  1. Database Query Optimization
    • OrderBy is expensive
    • Отдельный стоит дорого
    • RowCount дорого
    • GroupBy дорого
    • и т. д. Иногда вы не можете жить без этих вещей, но если вы можете обрабатывать некоторые из этих вещей в своем коде C#, это может быть быстрее.
  2. Индексация таблицы базы данных (для начала, индексируются ли поля в предложении WHERE?)
  3. Типы данных таблицы базы данных (используете ли вы наименьший из возможных, учитывая данные?)
  4. Why are you converting the datareader to an array?
    • e.g., would it serve just as well to create an adapter/datatable that you then would not need to convert to an array?
  5. Вы изучали Entity Framework? (может быть медленнее... но если у вас нет вариантов, возможно, стоит изучить, чтобы убедиться)

Просто случайные мысли. Не знаю, что может помочь в вашей ситуации.

person おたく    schedule 16.09.2010
comment
Заказ, группировка и т. д. быстрее обрабатываются в С#, чем в SQL? Это маловероятно, но, может быть, вы знаете что-то, чего не знаю я. - person Brandon Moore; 10.02.2012

Если при загрузке большого объема данных возникает проблема с реагированием, рассмотрите возможность использования асинхронных методов — BeginReader.

Я использую это все время для заполнения больших элементов графического интерфейса в фоновом режиме, в то время как приложение продолжает реагировать.

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

Часто для больших объемов данных вы можете оставить их в базе данных или позволить базе данных сделать всю тяжелую работу. Но нам нужно знать, какую обработку вы выполняете, которая требует всего этого в массиве одновременно.

person Cade Roux    schedule 16.09.2010
comment
Отзывчивость не проблема. - person watbywbarif; 17.09.2010