Я создаю многоразовый уровень доступа к данным для 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 как таковым.