Правильный способ передачи десятичной дроби и строки как SqlParameter - PullRequest
0 голосов
/ 28 января 2012

Я создаю многоразовый уровень доступа к данным для SQL Server для некоторых проектов. У меня проблема с поиском правильного способа передачи .NETs decimal в качестве параметра для запроса. Самый очевидный способ:

cmd.Parameters.AddWithValue("@P0", parameterValue);

работает почти хорошо. Значение правильно хранится в БД, но SqlClient выводит точный тип из фактического значения, поэтому, когда приложение передает 12345.678, оно объявляет @ P0 как NUMERIC(8,3). Когда точно такой же запрос используется с другим значением, объявляется точность и масштаб этого значения. По неизвестной мне причине в SQL Server эти запросы не равны, и каждый из них получает отдельную запись в sys.dm_exec_cached_plans. С string точно такая же проблема - для каждой длины существует свой план запроса.

Некоторые из наших приложений пишут довольно много записей в минуту, каждая из которых имеет значения 5-10 decimal с сильно изменяющимися диапазонами (некоторые данные датчика, некоторые значения валюты). Почти каждый INSERT получает свой собственный план запросов, и через несколько дней кэшируется более 100 000 версий одного и того же плана запросов, что занимает несколько ГБ ОЗУ.

Моя идея - объединить все возможные типы с несколькими произвольно выбранными типами. Для decimal, когда точность ниже 20, я устанавливаю его на 20. Когда точность больше 20, я устанавливаю его как наименьшее значение, делимое на 4, больше, чем фактическая точность (например, 24, 28, 32, 36). То же самое относится к шкале (минимум 2, затем шаги по 2) и строкам (минимум 128, затем степени 2). Этот способ, кажется, держит проблему под контролем - я видел около 100 вариантов планов для каждого запроса вместо 100 КБ, и SQL Server использует память для буферного пула, а не для некоторых бесполезных планов.

Есть ли способ, которым этот подход может пойти не так? Существуют ли более эффективные способы контроля кэша планов запросов при использовании SqlClient и запросов, загруженных с decimals?

Список вещей, которые я не могу сделать:

  • Используйте хранимые процедуры - потому что целью этого DAL является создание абстрактного слоя для многих СУБД (SQL Server, MS Access, Firebird, Oracle на данный момент).
  • Заставьте моих товарищей по команде как-то передавать фактический тип с каждой переменной - потому что это было бы жестоко.
  • Удалите этот DAL, используйте старый добрый DbProviderFactory и создайте параметры, как в 1990 году - потому что этот DAL также обрабатывает создание запросов для диалектов SQL, создание структуры БД и т. Д.
  • Удалите этот DAL и используйте «правильный» DAO, такой как NHibernate - потому что он не был изобретен здесь.
  • Отправьте этот вопрос на dba.stackexchange.com - потому что это проблема с SqlClient и тем, как я его использую, а не с SQL Server как таковым.

1 Ответ

2 голосов
/ 28 января 2012

Вы правильно определили ключевую проблему здесь: позволить драйверу SQL самостоятельно определять размеры, масштабы и точность ваших параметров.Ваша идея уменьшить количество планов запросов путем ограничения точности / масштабов / размеров параметров также звучит правильно.Для строк вы можете установить размер, равный наибольшему ожидаемому значению: он должен работать правильно, когда ваш запрос сравнивает строки параметров с ограничениями большого размера до varchar s меньшего размера.Выбор нескольких значений точности для десятичных дробей также звучит правильно.Посмотрите, сможете ли вы снизить его до одной пары точности / масштаба: это может быть возможно (это сработало очень хорошо для наших проектов на работе).Если вам удастся это сделать, вы сможете перейти к одному плану запросов для каждого запроса SQL.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...