Странный SQL Server ленивая загрузка табличных переменных? - PullRequest
0 голосов
/ 27 июня 2011

Я столкнулся с вводящей в заблуждение ошибкой в ​​SQL Server 2008, и мне интересно, может ли кто-нибудь объяснить, что со мной происходит?

У меня есть хранимая процедура примерно так:

declare @cross_reference table (
      context    varchar(20)    not null
    , value1     varchar(10)    not null
    , value2     varchar(10)    not null
)

insert into @cross_reference values ('map', 'from_value', 'to_value')
insert into @cross_reference values ('map', 'from_value', 'to_value')
insert into @cross_reference values ('map', 'from_value_xxxxx', 'to_value_xxxxxxx')

select 
    t1.field1
    , t1.field2
    , xref.value2
from table_1 t1
inner join table_2 t2 on t2.id = t1.id
left join @cross_reference xref on xref.context = 'map' and xref.value1 = t2.map_id 

фактический сохраненный процесс является более сложным, но это суть.

После запуска SP я получаю загрузку выходных строк до того, как произойдет ошибка «строки или двоичные данные будут усечены».Конкретные ссылки на строки в ошибке указывали где-то в главном операторе SELECT выше, но после некоторой отладки я обнаружил, что значения, которые я вставлял в перекрестную ссылку в начале, были слишком большими, и это исправило их.

Но мои вопросы таковы:

  • как SQL Server выполнял основной оператор SELECT, не заканчивая вставку строк перекрестных ссылок?Есть ли какая-то отложенная обработка?Ленивая загрузка табличных переменных?

  • С какой стати сообщение «обрезать строковые или двоичные данные» не указывает на то, где это происходит на самом деле?Или я делаю это неправильно?

Спасибо, Рэй

РЕДАКТИРОВАТЬ

Я думаю, что это должно быть что-то делать с LEFT JOIN на столпеременная и что ни один из его столбцов не участвует в предложении WHERE.Похоже, что SQL Server оставил подготовку таблицы до тех пор, пока она не понадобится (после завершения ВНУТРЕННИХ СОЕДИНЕНИЙ), и в этот момент произошла ошибка, когда большая часть набора результатов уже готова к SELECT.

также заметил, что значения, которые успешно вставлены в @cross_reference, отображаются в возвращаемом наборе результатов.В то время как строки, которые не удалось вставить из-за их слишком большого размера, просто показывают NULL.

Ответы [ 2 ]

1 голос
/ 27 июня 2011

Только потому, что произошла ошибка, это не останавливает выполнение сохраненного процесса.Вы не увидите сообщение об ошибке, потому что по умолчанию SSMS показывает таблицу результатов, пока запрос не завершит обработку.

Это показывает результаты в течение 10 секунд перед переключением на сообщение об ошибке:

RAISERROR('Error',16,1)
select top 1000 * from sys.objects so1,sys.objects so2,sys.objects so3
WAITFOR DELAY '00:00:10'

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

declare @cross_reference table (
      context    varchar(20)    not null
    , value1     varchar(10)    not null
    , value2     varchar(10)    not null
)

insert into @cross_reference (context,value1,value2)
values ('map', 'from_value', 'to_value'),
       ('map', 'from_value', 'to_value'),
       ('map', 'from_value_xxxxx', 'to_value_xxxxxxx');
if @@ERROR !=0 or @@ROWCOUNT !=3 return

Или, если вы не знаете количество строк, измените условие на @@ROWCOUNT = 0

(или, конечно,, используйте TRY / CATCH - но я сам еще не написал много кода, используя его, поэтому не могу просто привести пример)

Ваш текущий код сделал каждую вставку независимой - так чтовставки, которые могут работать, делать, а те, которые не могут, генерировать сообщения об ошибках.Затем он продолжает обработку вашего окончательного запроса.Поскольку таблица используется в LEFT JOIN, для конечного запроса, разумеется, не имеет значения, существуют ли любые строки в табличной переменной.

0 голосов
/ 27 июня 2011

Я не могу воспроизвести именно то, что вы описали.Одна вещь, которую я бы сказал, сосредоточив внимание на вставке данных в таблицу var, заключается в том, что если у вас есть ANSI_WARNINGS ON, то в точке вставки должна произойти ошибка.

т.е.

SET ANSI_WARNINGS ON -- Gives the truncation error 
DECLARE @T1 TABLE (value1 varchar(10) not null)
INSERT @T1 VALUES ('1234567890ABC')

SET ANSI_WARNINGS OFF -- Does not give the truncation error. "1234567890" will be inserted
DECLARE @T1 TABLE (value1 varchar(10) not null)
INSERT @T1 VALUES ('1234567890ABC')

У вас есть ANSI_WARNINGS ON или OFF для подключения?

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