Добро пожаловать в форум, Guest  >>   Войти | Регистрация | Поиск | Правила | В избранное | Подписаться
Все форумы / Microsoft SQL Server Новый топик    Ответить
 как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
Max_11111
Member

Откуда:
Сообщений: 201
У меня есть скрипт, копирующий таблицы с одного сервера на другой (с рабочего на тестовый с ограничением на количество строк).
В нём я в табличную переменную записываю запросы, которые нужно выполнить. Затем курсором по ней пробегаюсь и выполняю их командой EXEC.
Таблицы я копирую запросом SELECT INTO, заметил что на этом этапе вываливается ошибка: Не удалось найти базу данных с идентификатором 22 и именем "22". Возможно, база данных находится в режиме "вне сети". Подождите несколько минут и повторите попытку.
Если я выполняю запросы, хранящиеся в табличной переменной, по очереди сам, то они отрабатывают. Ломаются только когда выполняю их курсором. Заметил некоторую особенность:
OPEN db_cursor
FETCH NEXT FROM db_cursor INTO @Command   
WHILE @@FETCH_STATUS = 0   
BEGIN
	-- Добавим обработку ошибок
	BEGIN TRY  
		select getdate(), @Command
		EXECUTE @res = sp_executesql @Command
		select getdate(), @res
	END TRY
	BEGIN CATCH
		-- Сохраним ошибки
		SET @log = @log + CHAR(10) + @Command + ' ' + ERROR_MESSAGE()
	END CATCH

	FETCH NEXT FROM db_cursor INTO @Command
END

Я добавил вывод времени до и после выполнения команды EXEC, и увидел что эта команда не ждёт выполнения запроса, а запускает следующие запросы. Если запрос select into работает пару секунд, и таких запросов одновременно штук 10 запущено, то SQL Server не ждёт пока они все завершатся, и завершает их с ошибкой.
Почему так происходит, и можно ли сделать так чтобы EXECUTE ждал выполнения операции, прежде чем идти дальше?
26 июл 16, 07:11    [19454636]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31785
Max_11111
Я добавил вывод времени до и после выполнения команды EXEC, и увидел что эта команда не ждёт выполнения запроса, а запускает следующие запросы.
Эта команда ждёт выполнения запроса.
Max_11111
SQL Server не ждёт пока они все завершатся, и завершает их с ошибкой.
с какой ошибкой?
Max_11111
Если запрос select into работает пару секунд
Не нашёл в коде select into

Вы результат выполнения представьте, а ещё лучше репро.
26 июл 16, 10:38    [19455313]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31785
Max_11111,

Вы лучше уберите BEGIN TRY, и прочитайте то, что выводит сервер.
Именно так отлаживают, а не говорят "не работает" без подробностей.
26 июл 16, 10:40    [19455333]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
Ролг Хупин
Member

Откуда: Чебаркуль
Сообщений: 3990
alexeyvg
Max_11111,

Вы лучше уберите BEGIN TRY, и прочитайте то, что выводит сервер.
Именно так отлаживают, а не говорят "не работает" без подробностей.


почему бы не вывести сообщение

BEGIN CATCH
-- Сохраним ошибки
SET @log = @log + CHAR(10) + @Command + ' ' + ERROR_MESSAGE()
select @log as 'sluchilos dosadnoe nedorazumenie'
END CATCH
26 июл 16, 10:57    [19455473]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
alexeyvg
Member

Откуда: Moscow
Сообщений: 31785
Ролг Хупин
alexeyvg
Max_11111,

Вы лучше уберите BEGIN TRY, и прочитайте то, что выводит сервер.
Именно так отлаживают, а не говорят "не работает" без подробностей.

почему бы не вывести сообщение

BEGIN CATCH
-- Сохраним ошибки
SET @log = @log + CHAR(10) + @Command + ' ' + ERROR_MESSAGE()
select @log as 'sluchilos dosadnoe nedorazumenie'
END CATCH
Тут ещё тонкость, ERROR_MESSAGE() не выводит все ошибки :-(

Надёжнее всё таки убрать CATCH для отладки, и проще, это проще, зачем плодить сущности сверх необходимого?
26 июл 16, 11:03    [19455525]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
Max_11111
Member

Откуда:
Сообщений: 201
alexeyvg
с какой ошибкой?

Не удалось найти базу данных с идентификатором 22 и именем "22". Возможно, база данных находится в режиме "вне сети". Подождите несколько минут и повторите попытку

alexeyvg
Не нашёл в коде select into

Список запросов такого вида:
SELECT * INTO [db].[dbo].[table1] FROM OPENQUERY([server], 'SELECT TOP (10000) * FROM [db].[dbo].[table1] WITH (NOLOCK)');
SELECT * INTO [db].[dbo].[table2] FROM OPENQUERY([server], 'SELECT TOP (10000) * FROM [db].[dbo].[table2] WITH (NOLOCK)');
SELECT * INTO [db].[dbo].[table3] FROM OPENQUERY([server], 'SELECT TOP (10000) * FROM [db].[dbo].[table3] WITH (NOLOCK)');


alexeyvg
Вы лучше уберите BEGIN TRY, и прочитайте то, что выводит сервер.

убрал. сообщения об ошибках не вывелись, но выполнился только один SELECT INTO, затем Management studio отключила меня от сервера


Ролг Хупин
почему бы не вывести сообщение

SELECT * INTO [db].[dbo].[table1] FROM OPENQUERY([server], 'SELECT TOP (10000) * FROM [db].[dbo].[table1] WITH (NOLOCK)'); Не удалось найти базу данных с идентификатором 22 и именем "22". Возможно, база данных находится в режиме "вне сети". Подождите несколько минут и повторите попытку
26 июл 16, 11:59    [19455984]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
Max_11111
Member

Откуда:
Сообщений: 201
До копирования таблиц у меня идёт пересоздание базы:
USE [master]
EXEC msdb.dbo.sp_delete_database_backuphistory @database_name = [db]
USE [master]; IF EXISTS (SELECT 1 FROM sys.databases WHERE name = 'db') BEGIN ALTER DATABASE [db] SET SINGLE_USER WITH ROLLBACK IMMEDIATE END
USE [master]; IF EXISTS (SELECT 1 FROM sys.databases WHERE name = 'db') BEGIN DROP DATABASE [db] END
CREATE DATABASE [db]


До этого создавал таблицы в базе [db], сейчас создал в [db_test]. Один и тот же скрипт в [db] выдаёт ошибку (описанную выше), а в [db_test] отрабатывает без ошибок и всё создаёт. Почему так? есть какие-то настройки базы, не удаляющиеся после её удаления?
26 июл 16, 12:03    [19456014]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
Konst_One
Member

Откуда:
Сообщений: 11568
[server]

вот тут ищите свою проблему, что там за линкованный сервер и под каким логином вы туда попадаете
26 июл 16, 12:05    [19456025]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
Max_11111
Member

Откуда:
Сообщений: 201
Konst_One,

А при чём тут линкованый сервер? прочитайте следующее моё сообщение
26 июл 16, 12:14    [19456075]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
o-o
Guest
огласите версию сервера.
похоже, это баговина.
хотя про то, что курсор переходит к след. строке, не дождавшись завершения execute, это какой-то фантастиш.
---
мне просто стало интересно, как воспроизвести
Msg 615 Could not find database ID %d, name '%.*ls'. The database may be offline. Wait a few minutes and try again.

если база в оффлайне, выдается вполне конкретное
Msg 942, Level 14, State 4, Line 1
Database 'db2' cannot be opened because it is offline.


или если она ресторится, или в саспекте, или просто нет такой базы,
сообщения всегда конкретные:
Msg 927, Level 14, State 2, Line 1
Database 'turk' cannot be opened. It is in the middle of a restore.

Msg 926, Level 14, State 1, Line 1
Database 'cyr_100' cannot be opened. It has been marked SUSPECT by recovery. See the SQL Server errorlog for more information.

Msg 208, Level 16, State 1, Line 1
Invalid object name 'db10.dbo.t'.


а вот чтобы получить Msg 615,
пришлось покопаться в гугле.
выпадает коннект:
Could not find database ID 0, name 'dbname'. The database may be offline. Wait a few minutes and try again.
26 июл 16, 12:17    [19456091]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
Max_11111
Member

Откуда:
Сообщений: 201
o-o,

оба сервера:
Microsoft SQL Server Enterprise (64-bit)
11.0.5343.0
26 июл 16, 12:19    [19456104]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
Max_11111
Member

Откуда:
Сообщений: 201
o-o,

базу данных с идентификатором 22 и именем "22"

Если смотреть таблицу sys.databases, то у этой БД database_id=11, а максимальный database_id = 21. т.е. БД с идентификатором 22 просто не существует
26 июл 16, 12:24    [19456150]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
aleks2
Guest
Max_11111
Список запросов такого вида:
SELECT * INTO [db].[dbo].[table1] FROM OPENQUERY([server], 'SELECT TOP (10000) * FROM [db].[dbo].[table1] WITH (NOLOCK)');
SELECT * INTO [db].[dbo].[table2] FROM OPENQUERY([server], 'SELECT TOP (10000) * FROM [db].[dbo].[table2] WITH (NOLOCK)');
SELECT * INTO [db].[dbo].[table3] FROM OPENQUERY([server], 'SELECT TOP (10000) * FROM [db].[dbo].[table3] WITH (NOLOCK)');


Скорее всего, сервер просто саботирует этот идиотизм.
26 июл 16, 12:44    [19456305]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
o-o
Guest
вы репро видели на коннекте?
+ repro
CREATE DATABASE test1
go

USE test1
go

CREATE type dbo.tvp1 as table ( id int, name varchar(128) )
GO

CREATE table dbo.table1 ( id int, name varchar(128) )
GO

CREATE FUNCTION dbo.fn11
    (
     @CompanyId INT
    , @Data dbo.tvp1 READONLY
    )
RETURNS TABLE
AS
    RETURN
    (
        WITH    cteall ( id, NAME )
                 AS ( SELECT id
                             , NAME
                     FROM     dbo.table1
                     WHERE    id NOT IN ( SELECT id FROM @Data )
                                AND name IN ( SELECT name FROM @Data )
                     )
                    SELECT id
                         , NAME
                         , @companyId AS CompanyId
                    FROM    cteall        
        )
GO

DECLARE @companyId INT = 12106
DECLARE @tvp dbo.tvp1

INSERT INTO @tvp ( id, Name)
VALUES (1, '1')

SELECT id, name
from dbo.fn11(@companyId, @tvp )

если их код запустить, вываливает
Msg 615, Level 21, State 1, Line 7
Could not find database ID 0, name 'test1'. The database may be offline. Wait a few minutes and try again.


а уж у новой-то базы Test1 id никакой не 0, а 67.
т.е. вы тоже напоролись на баг, пишут, починили в след. версии,
написано это в 2011-ом.
сейчас проверю на 2012-ом и 14-ом
26 июл 16, 12:48    [19456349]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
o-o
Guest
Max_11111
o-o,

оба сервера:
Microsoft SQL Server Enterprise (64-bit)
11.0.5343.0

вот на таком уже не воспроизводится:
version
Microsoft SQL Server 2012 - 11.0.5569.0 (Intel X86) Jan 9 2015 11:41:41 Copyright (c) Microsoft Corporation Developer Edition on Windows NT 6.1 <X86> (Build 7601: Service Pack 1)

но вообще убойная ошибка,
Severity: 21, с разрывом соединения.
попробуйте накатить последнее CU,
а если ошибка не уйдет,
написать репро и снова им на коннект запостить
26 июл 16, 13:22    [19456661]     Ответить | Цитировать Сообщить модератору
 Re: как сделать так чтобы функция EXECUTE ждала выполнения запущенного кода, а не шла дальше?  [new]
Max_11111
Member

Откуда:
Сообщений: 201
o-o,

Накатил Cumulative Update Package 13 for SQL Server 2012 SP2 - KB3165266, обновил до версии 11.0.5655.0
Всё работает!
Спасибо за помощь.
27 июл 16, 13:15    [19461844]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить