2014-10-13 3 views
2

Мы используем CLR-функции в наших ETL-процессах, чтобы централизовать логику обработки данных и проверку данных. Эти функции являются довольно базовыми и не требуют доступа к данным и детерминированы для обеспечения параллелизма.Производительность сервера CLR sql

Например:

[SqlFunction(DataAccess = DataAccessKind.None, IsDeterministic = true, SystemDataAccess = SystemDataAccessKind.None, IsPrecise = true)] 
public static bool check_smallint(string input) 
{ 
    string teststring; 
    try 
    { 
     teststring = input.Trim(' ').Replace('-', '0'); 
     if (teststring.Length == 0) 
     { 
      teststring = "0"; 
     } 
     Convert.ToInt16(teststring); 
    } 
    catch (NullReferenceException) 
    { 
     return true; 
    } 
    catch (FormatException) 
    { 
     return false; 
    } 
    catch (OverflowException) 
    { 
     return false; 
    } 
    return true; 
} 

Это прекрасно работает для исполнения за исключением. Query значительно замедлились, что создает проблемы при обработке больших наборов данных (миллионы строк и т. Д.).

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

Пожалуйста, не предлагайте разные решения, мы уже рассматриваем их, как встроенный sql, или совершенно другой подход. Стандартные sql-функции во многих случаях не имеют возможности из-за отсутствия ошибок.

PS. Мы используем SQL 2008R2.

+0

Спасибо для вашего комментария. Мы пытаемся это сделать прямо сейчас. –

ответ

5

с накладными расходами на создание нового соединения или выделение памяти для каждого вызова функции. Таким образом, решение может быть соединением/объединением памяти.

Это не то, о чем вам нужно беспокоиться на стороне C#. Вы не выделяете память (конечно, вы выделяете строки и вещи, которые вам нужны внутри вашей функции, вы не можете объединить/повторно использовать). Также вам не о чем беспокоиться.

Это работает отлично, за исключением исполнения.

Ваш код делает что-то невероятно ... ИСКЛЮЧИТЕЛЬНО ... медленно: метание исключения вместо выполнения проверки. Исключением является экспансивная операция и должна использоваться для обработки исключительных ситуаций (только 100/200 записей с null - или недопустимым значением, и это замедлит запрос более чем 1 000 000 записей). Неверный формат ввода или значения null в столбце базы данных ... не являются исключительными (этот стиль программирования - исключения вместо проверок - разрешен и даже рекомендуется на других языках, таких как Python. Я бы вообще избегал этого в C#. Конечно, здесь не уместно, где проблема с производительностью).

public static bool check_smallint(string input) 
{ 
    if (String.IsNullOrWhiteSpace(input)) 
     return true; 

    short value; 
    return Int16.TryParse(input, out value); 
} 

Обратите внимание, что: String.IsNullOrWhiteSpace(input) возвратит true для null входов или струны, сделанные только из пространств (замене Trim() и NullReferenceException вещи). Все остальное (FormatException для ввода текста, который не является целым числом или слишком большим числом с OverflowException) обрабатывается Int16.TryParse(). Код короче (и немного быстрее) для действительных входов, но это во много раз быстрее для недействительных единиц.

+0

'OUT' должен быть указан для параметра значения метода TryParse. –

+0

@ DanGuzman-SQLServerMVP да, опечатка. Исправлено, tnx! –

+0

@AdrianoRepetti +1 для гораздо лучшего подхода (т. Е. Не полагаясь на исключения). Просто FYI, дополнительное улучшение будет заключаться в использовании правильных типов 'SqlTypes' для параметров вместо типов .NET. Я добавил ответ, объясняющий это более подробно. –

2

Я делаю это отдельным ответом вместо комментария к ответу @ Адриано, так что его вряд ли упускают (так как не все читают все комментарии).


В дополнение к изменению подхода, предложенный @Adriano, вы действительно должны использовать соответствующие типы данных, найденных в System.Data.SqlTypes Namespace, для всех параметров ввода/вывода и возвращаемых значений. Существуют некоторые важные различия и преимущества для их использования, например, все они имеют свойство .IsNull. Полный список отличий слишком много информации, чтобы поместить здесь, но я задокументировать его в следующей статье: Stairway to SQLCLR Level 5: Development (Using .NET within SQL Server)

Адаптирования @ код Адриана использовать соответствующие типы дадут вам следующее:

public static SqlBoolean check_smallint(SqlString input) 
{ 
    if (input.IsNull) 
     return true; 

    if (input.Value.Trim() == String.Empty) 
     return true; 

    short value; 
    return Int16.TryParse(input.Value, out value); 
} 
+0

My upvote: Я пишу этот код с таким же * чувством * простого кода на C#, я не знал, что есть какая-либо польза для использования типов SqlXyz. Приятно знать, у меня есть некоторые ТЯЖЕЛЫЕ функции, которые будут иметь большую выгоду от любого улучшения! –

+0

@AdrianoRepetti Спасибо. И я надеюсь, что эта информация поможет. Также проверьте остальную часть серии [Stairway to SQLCLR] (http://www.sqlservercentral.com/stairway/105855/) :). И, конечно, всегда есть [SQL #] (http://SQLsharp.com/) (который я автор). –

Смежные вопросы