Является ли код SQL быстрее, чем код С#?
Несколько месяцев назад я начал работать в этой компании по программированию. Один из методов, которые они используют, - это сделать как можно больше работы в SQL, а не в С#.
Итак, скажем, у меня есть этот простой пример написания списка некоторых файлов:
Что-то вроде этого:
string SQL = @"
SELECT f.FileID,
f.FileName,
f.FileExtension,
'/files/' + CAST(u.UserGuid AS VARCHAR(MAX)) + '/' + (f.FileName + f.FileExtension) AS FileSrc,
FileSize=
CASE
WHEN f.FileSizeB < 1048576 THEN CAST(CAST((f.FileSizeB / 1024) AS DECIMAL(6, 2)) AS VARCHAR(8)) + ' KB'
ELSE CAST(CAST((f.FileSizeB / 1048576) AS DECIMAL(6, 2)) AS VARCHAR(8)) + ' MB'
END
FROM Files f
INNER JOIN Users u
ON f.UserID = u.UserID
";
// some loop for writing results {
// write...
// }
Быстрее или лучше, чем-то вроде этого:
string SQL = @"
SELECT u.UserGuid,
f.FileID,
f.FileName,
f.FileExtension,
f.FileSizeB
FROM Files f
INNER JOIN Users u
ON f.UserID = u.UserID";
// some loop for writing results {
string FileSrc = "/Files/" + result["UserGuid"] + "/" + result["FileName"] + result["FileExtension"];
string FileSize = ConvertToKbOrMb(result["FileSizeB"]);
// write...
// }
Этот конкретный код не имеет значения (это всего лишь некоторый базовый пример)... вопрос об этом вообще вообще... лучше ли разместить большую нагрузку на SQL или "нормальный" код?
Ответы
Ответ 1
Это просто плохая практика программирования. Вы должны разделить и изолировать различные части своей программы для удобства дальнейшего обслуживания (подумайте о следующем программисте!)
Производительность
Многие решения страдают от плохой производительности БД, поэтому большинство разработчиков обычно ограничивают доступ базы данных SQL к самой маленькой транзакции. В идеале преобразование необработанных данных в удобочитаемую форму должно происходить в самом последнем пункте. Также использование памяти в неформатированных данных намного меньше, и, хотя память дешевая, вы не должны ее тратить. Каждый дополнительный байт, который буферизуется, кэшируется и передается, занимает все время и снижает доступные ресурсы сервера.
например. для форматирования веб-приложения должны выполняться локальные шаблоны JavaScript из пакета данных JSON. Это уменьшает рабочую нагрузку базы данных SQL и серверов приложений и сокращает данные, которые необходимо передать по сети, что ускоряет производительность сервера
Форматирование и локализация
Многие решения имеют разные выходные потребности для одной и той же транзакции, например. разные взгляды, разные локализации и т.д. Встраиваясь в транзакцию SQL, вам нужно будет сделать новую транзакцию для каждой локализации, это станет кошмаром обслуживания
Также форматированные транзакции не могут использоваться для интерфейса API, вам понадобится еще один набор транзакций для интерфейса API, который не имеет форматирования
С помощью С# вы должны использовать хорошо протестированный шаблон или библиотеку обработки строк или, по крайней мере, string.Format(), не используйте оператор "+" со строками, он очень медленный
Поделиться загрузкой
Большинство решений имеют несколько клиентов для одного БД, поэтому загрузка форматирования на стороне клиента используется совместно с процессорами нескольких клиентов, а не с одним процессором базы данных SQL
Я серьезно сомневаюсь, что SQL быстрее, чем С#, вы должны выполнить простой тест и опубликовать результаты здесь: -)
Ответ 2
Причина, по которой вторая часть может быть немного медленнее, - , потому что вам нужно вытащить данные с SQL-сервера и передать ее части кода С#, и это занимает больше времени.
Чем больше вы читаете, тем больше ConvertToKbOrMb(result["FileSizeB"])
может занять некоторое время, а также зависеть от вашего уровня DAL. Я вижу некоторые DAL, которые очень медленны.
Если вы оставите их на SQL Server, вы получите эту дополнительную обработку вывода данных, вот и все.
Из опыта одна из моих оптимизаций - всегда извлекать только нужные данные. Чем больше данных вы читаете на сервере sql и переместите их на все (asp.net, console, С# program и т.д.), тем больше времени вы потратьте их на перемещение, особенно если они большие строки или сделать много конверсий из строки в числа.
Чтобы ответить и на прямой вопрос, что быстрее - я говорю, что вы не можете их сравнить. Они оба как можно быстрее, если вы делаете хороший код и хорошие запросы. SQL Server также хранит много статистики и улучшает возвращаемый запрос - С# не имел такой части, так что сравнить?
Один тест сам по себе
Хорошо, у меня есть много данных из проекта и сделайте быстрый тест, который на самом деле не доказывает, что тот быстрее, чем другой.
Что я запускаю два случая.
SELECT TOP 100 PERCENT cI1,cI2,cI3
FROM [dbo].[ARL_Mesur] WITH (NOLOCK) WHERE [dbo].[ARL_Mesur].[cWhen] > @cWhen0;
foreach (var Ena in cAllOfThem)
{
// this is the line that I move inside SQL server to see what change on speed
var results = Ena.CI1 + Ena.CI2 + Ena.CI3;
sbRender.Append(results);
sbRender.Append(Ena.CI2);
sbRender.Append(Ena.CI3);
}
против
SELECT TOP 100 PERCENT (cI1+cI2+cI3) as cI1,cI2,cI3
FROM [dbo].[ARL_Mesur] WITH (NOLOCK) WHERE [dbo].[ARL_Mesur].[cWhen] > @cWhen0;
foreach (var Ena in cAllOfThem)
{
sbRender.Append(Ena.CI1);
sbRender.Append(Ena.CI2);
sbRender.Append(Ena.CI3);
}
и результаты показывают, что скорость близка к той же.
- Все параметры double
- Чтение оптимизировано, я вообще ничего не читаю, просто переместите обработку с одной части на другую.
В 165,766 строк приведены следующие результаты:
Start 0ms +0ms
c# processing 2005ms +2005ms
sql processing 4011ms +2006ms
Start 0ms +0ms
c# processing 2247ms +2247ms
sql processing 4514ms +2267ms
Start 0ms +0ms
c# processing 2018ms +2018ms
sql processing 3946ms +1928ms
Start 0ms +0ms
c# processing 2043ms +2043ms
sql processing 4133ms +2090ms
Таким образом, на скорость может влиять множество факторов... мы не знаем, что представляет собой проблема вашей компании, что делает С# медленнее, чем обработка sql.
Ответ 3
Как общее правило: SQL предназначен для управления данными, а не для форматирования его отображения.
Сделайте столько, сколько сможете в SQL, да, но только до тех пор, пока он служит этой цели. Я бы очень долго смотрел на ваш "пример SQL" исключительно на этом основании. Ваш "пример С#" выглядит как более четкое разделение обязанностей для меня.
Сказав это, не заходите слишком далеко и переставайте делать что-то в SQL, которое должно выполняться в SQL, например, для фильтрации и объединения. Например, переопределение INNER JOIN Users u ON f.UserID = u.UserID
в С# было бы катастрофой, с точки зрения производительности.
Что касается производительности в этом конкретном случае:
Я бы ожидал, что "пример С#" (не все С#, только этот пример) будет немного быстрее, просто потому, что...
f.FileSizeB
... выглядит уже...
'/files/' + CAST(u.UserGuid AS VARCHAR(MAX)) + '/' + (f.FileName + f.FileExtension) AS FileSrc,
FileSize=
CASE
WHEN f.FileSizeB < 1048576 THEN CAST(CAST((f.FileSizeB / 1024) AS DECIMAL(6, 2)) AS VARCHAR(8)) + ' KB'
ELSE CAST(CAST((f.FileSizeB / 1048576) AS DECIMAL(6, 2)) AS VARCHAR(8)) + ' MB'
END
..., который должен сохранить некоторую пропускную способность сети. И пропускная способность сети имеет ограниченный ресурс, чем процессор (особенно на стороне клиента).
Конечно, ваш пробег может отличаться, но в любом случае разница в производительности может быть достаточно маленькой, поэтому другие проблемы, такие как общая ремонтопригодность кода, становятся относительно более важными. Честно говоря, ваш "пример С#" выглядит мне лучше в этом отношении.
Ответ 4
На сервере базы данных есть все основания делать все возможное. Сведение к минимуму количества данных, которые необходимо передать назад и вперед, и предоставление серверу большей свободы в оптимизации процесса - это хорошо.
Однако это не показано на примере. Оба процесса передают столько данных взад и вперед (возможно, первые пропускают больше), и единственное различие заключается в том, кто выполняет расчет, и может быть, что клиент делает это лучше.
Ответ 5
Ваш вопрос о том, должны ли выполняться операции манипулирования строкой в С# или SQL. Я бы сказал, что этот пример настолько мал, что любое увеличение производительности - одностороннее или другое - не имеет значения. Вопрос в том, "где это должно быть сделано"?
Если код является "одноразовым" кодом для части приложения, то выполнение на уровне приложения имеет большой смысл. Если этот код повторяется во всем приложении, вы хотите его инкапсулировать. Я хотел бы утверждать, что лучший способ инкапсулировать его - использовать вычисляемый столбец SQL Server, представление, функцию, основанную на таблицах, или скалярную функцию (при этом в этом случае предпочтительный вычисленный столбец является предпочтительным). Это гарантирует, что одна и та же обработка происходит одинаково независимо от того, где вызывается.
Существует ключевое различие между кодом базы данных и кодом С# с точки зрения производительности. Код базы данных автоматически запускается параллельно. Итак, если ваш сервер базы данных многопоточен, то отдельные потоки могут выполнять эти строковые манипуляции одновременно (no promises, ключевое слово здесь "возможно" ).
В общем, думая о расколе, вы хотите свести к минимуму количество данных, передаваемых взад и вперед. Разница в этом случае кажется минимальной.
Итак, если это одно место в приложении, которое имеет эту логику, то сделайте это в приложении. Если приложение заполнено ссылками на эту таблицу, которые хотят эту логику, тогда подумайте о вычисленном столбце. Если приложение имеет много похожих запросов в разных таблицах, тогда подумайте о скалярной функции, хотя это может повлиять на способность запросов использовать parallelism.
Ответ 6
Это действительно зависит от того, что вы делаете.
Не забывайте о SQL CLR. Существует много операций, в которых код T-SQL работает только медленнее.
Ответ 7
Обычно в производственных средах уровень инфраструктуры базы данных предоставляется дважды в три раза больше ресурсов, чем уровень приложения.
Кроме того, для SQL-кода, запускаемого изначально для базы данных, будет иметь большое преимущество в том, что SQL-код запускается в приложении и проходит через драйвер базы данных.