SQL Trace / Profiler - отображается неоднозначный формат даты (.NET Core / EF) - PullRequest
0 голосов
/ 15 января 2019

У нас установлен экземпляр SQL Server 2008R2 с английским языком (США). SSMS> Экземпляр> Свойства> Общие.

У нас есть логин с языком по умолчанию "британский английский". SSMS> Безопасность> Вход в систему> Пользователь> Свойства.

Внешнее приложение .NET Core генерирует оператор вставки (EF) через форму / веб-API, который создает системную хранимую процедуру sp_executesql с использованием имени входа, установленного выше.

Используя SQL Server Profiler, я вижу, что сгенерированный SQL вставки содержит строковые даты в формате 'yyyy-mm-dd'. Например "2019-01-15 10:59:19.410".

Перед выполнением оператора существует exec sp_reset_connection, за которым следуют следующие операторы SET (я полагаю, это как-то связано с совместным использованием пула соединений для обеспечения правильных настроек для каждого входа в систему).

-- network protocol: LPC
set quoted_identifier on
set arithabort off
set numeric_roundabort off
set ansi_warnings on
set ansi_padding on
set ansi_nulls on
set concat_null_yields_null on
set cursor_close_on_commit off
set implicit_transactions off
set language British
set dateformat dmy
set datefirst 1
set transaction isolation level read committed

Что меня смущает, так это то, что оператор выполняется успешно, хотя в формате yyyy-mm-dd есть даты, а среда настроена как британский английский (DMY). Например - "2019-01-15 10:59:19.410".

Я узнал, что «2019-01-15 10: 59: 19.410» будет интерпретироваться как 1-й день 15-го месяца 2019 года, если DMY является текущей настройкой.

Например, это не удастся, так как SQL попытается интерпретировать строку даты как гггг-дд-мм

SET LANGUAGE [British English];

SELECT
    CAST('2019-01-13' AS DATETIME);

Сообщение 242, Уровень 16, Состояние 3, Строка 3 Преобразование данных varchar тип в тип данных datetime, приведший к значению вне допустимого диапазона.

Установка языка на английский (us_english) изменяет интерпретацию строки на MDY, и вышеуказанное утверждение работает.

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

Я не могу понять, почему оператор выполняется успешно. Очевидно, что существуют неявные приведения из строк даты в типы DATETIME.

Если я скопирую оператор из профилировщика SQL и вставлю в SSMS и попытаюсь выполнить для той же базы данных / того же пользователя, то произойдет сбой, как я и ожидал.

Сообщение 8114, уровень 16, состояние 1, строка 14 Ошибка преобразования типа данных varchar на сегодняшний день.

Итак ...

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

Я прошу прощения, если это не очень хорошо объяснено.

Ответы [ 2 ]

0 голосов
/ 17 января 2019

Я только что наткнулся на этот блог, который объясняет это очень четко - https://weblogs.sqlteam.com/dang/2007/10/11/sql-trace-parameter-values-are-not-always-as-they-seem/

Изображения по вышеуказанной ссылке больше не доступны (изначально опубликовано в 2007 году).

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

Надеюсь, это кому-нибудь поможет.

Блог Дэна Гусмана

Значения параметров трассировки SQL не всегда такие, какими они кажутся в четверг, 11 октября 2007 г., Дан Гузман

Я наткнулся на удивительное поведение SQL Trace / Profiler, которое мне кажется Стоит отметить. Значения параметров в трассировке RPC начальные / завершенные события не являются значениями, которые SQL Server использует для выполнить запрос. Вот пример, который я недавно обнаружил, который показывает это поведение. Я запустил следующий код C # для выполнения параметризованного запрос "SELECT @DateTime" со значением параметра, установленным на 11 октября, 2007. Сообщение консоли подтвердило, что SQL Server вернул ожидаемую дату.

Я вставил скрипт из трассировки и запустил его с SQL Server Окно запросов Management Studio. Вот след сценария SSMS выполнение:

Несмотря на то, что SQL выглядит одинаково, запрос SSMS вернул другая дата («10 ноября 2007 г.»), чем заявка («октябрь» 11, 2007 ")! Что с тобой? Зачем возвращался тот же сценарий? разные значения при запуске из кода приложения или Management Studio (или Query Analyzer), даже с идентичными настройками сеанса?

Причиной различий в поведении является класс событий трассировки. трассировка приложения показала событие RPC: завершено, но сеанс SSMS трассировка показала SQL: BatchCompleted. У обоих был один и тот же «исполнитель» sp_executesql… »в TextData. Хотя след сообщил об одном и том же TextData для обоих событий, SQL Server обработал RPC отличается от пакета SQL, и трассировка не показала полная история для события RPC.

Проблема в том, что значение входного параметра datetime для события RPC на самом деле не был включен в оператор SQL, как след RPC: завершено событие. Фактическое значение параметра datetime, которое SQL Server, используемый во время выполнения RPC, был передан на нативном (т.е. бинарный) формат через низкоуровневый протокол TDS. Трассировка TextData была только пересмотренное строковое представление этого значения, а чем фактическое значение, используемое SQL Server.

Напротив, пакет, отправленный SSMS, не был параметризован, поэтому SQL Server необходимо проанализировать строковое значение datetime в пакетном тексте. строка даты и времени "2007-10-11 00: 00: 00: 000" (генерируется трассировкой, а не передается приложением) является неоднозначным и интерпретируется по-разному в зависимости на настройку DATEFORMAT. Из-за настройки "DATEFORMAT DMY" в сценарий, значение строки даты было (неправильно) интерпретировано как 10 ноября, 2007 вместо 11 октября 2007 года. Параметр DATEFORMAT не имел влияет на RPC (параметризованное значение), поскольку настройка влияет только разбор строки, а не собственное значение даты и времени, предоставленное применение.

Я обнаружил эту проблему, когда помогал пользователю, который работал с SQL Server на французском языке (именно поэтому я указал DATEFORMAT DMY) устранить проблему с параметром даты и времени. Данные трассировки привели меня вниз неправильный путь, потому что это не сразу щелкнуло мной, что 1) DATEFORMAT не влияет на параметры даты и времени RPC и 2) трассировать RPC TextData не используется для выполнения запроса в любом случае. Я подал Connect отзывы об этом, чтобы предложить, чтобы SQL Trace / Profiler был изменен на сериализовать значения даты и времени RPC в нейтральном формате DATEFORMAT, например «2007-10-11T00: 00: 00: 000» или «20071011 00: 00: 00: 000». Это будет обеспечивают такое же поведение, когда трассировка TextData SQL выполняется как Пакет и быть немного более интуитивным при анализе данных трассировки.

Авторские права © 2018 - Дан Гузман

0 голосов
/ 15 января 2019

На самом деле происходит то, что Entity Framework генерирует параметризованные операторы, которые затем передаются на сервер с использованием (двоичного) протокола TDS, как приложения взаимодействуют с SQL Server. DATETIME значения, передаваемые в качестве параметров RPC, не передаются в виде строк - они передаются в виде байтовых последовательностей, которые представляют точное значение (например, 2019-01-15T10:59:19.410 представляется как D6 A9 00 00 AF 16 B5 00 при отправке в виде DATETIME (два маленьких -евские целые числа). (Отказ от ответственности: я на самом деле не проверял анализатор пакетов, поэтому, возможно, я неправильно понял байты).

Когда эти профилированные операторы представляются SQL Profiler, как если бы они были текстовыми пакетами, он переформатирует значения в строки, поскольку T-SQL не имеет собственного литерального формата для значений DATETIME. К сожалению, это происходит с форматом, который не гарантирует круговую передачу при всех возможных языковых настройках, что следует считать ошибкой в ​​Profiler. Все, чего не хватает, это T, но это важное упущение.

Нечто подобное происходит с таинственными вызовами exec sp_reset_connection, которые вы можете видеть, как засоряющие следы всех приложений, использующих пул соединений - ни одно приложение фактически не генерирует эти вызовы, и если вы попытаетесь выполнить этот оператор в Management Studio, вы увидите что нет процедуры sp_reset_connection. На уровне протокола в заголовке пакета есть только бит «сбросить это соединение», который преобразуется в фиктивный вызов с фиктивными операторами SET, представляющими текущие параметры, когда он представляется как оператор или трассировка события.

Вкратце: ваши приложения работают нормально, но если вы хотите точно воспроизвести то, что происходит, когда они выполняют вызовы, вставка копии в Profiler не подойдет.

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