SQL Server (TSQL) - возможно ли выполнять операторы EXEC параллельно? - PullRequest
14 голосов
/ 31 декабря 2010

SQL Server 2008 R2

Вот упрощенный пример:

EXECUTE sp_executesql N'PRINT ''1st '' + convert(varchar, getdate(), 126) WAITFOR DELAY ''000:00:10'''
EXECUTE sp_executesql N'PRINT ''2nd '' + convert(varchar, getdate(), 126)'

Первый оператор напечатает дату и задержку за 10 секунд до продолжения.Второе утверждение должно быть напечатано немедленно.

Как работает T-SQL, 2-е утверждение не будет оцениваться, пока не выполнится первое.Если я скопирую и вставлю его в новое окно запроса, оно будет выполнено немедленно.

Проблема в том, что у меня происходят другие, более сложные вещи с переменными, которые необходимо передать обеим процедурам.

Я пытаюсь сделать следующее:

  • Получить запись
  • Блокировать ее на период времени
  • , пока она заблокирована,выполнить некоторые другие операторы для этой записи и самой таблицы

Возможно, есть способ динамически создать пару рабочих мест?

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

Есть ли способ EXEC без ожидания / параллельно?

Ответы [ 5 ]

17 голосов
/ 31 декабря 2010

Да, есть способ, см. Асинхронное выполнение процедуры .

Однако, скорее всего, это не то, что вам нужно. T-SQL - это язык доступа к данным , и если принять во внимание транзакции, семантика блокирования и фиксации / отката почти невозможна для параллельной работы. Параллельный T-SQL работает, например, с очередями запросов , где каждый запрос независим и нет корреляции между заданиями.

То, что вы описываете, совсем не похоже на то, что может и не должно быть на самом деле параллелизировано.

2 голосов
/ 31 декабря 2010

Если вы хотите заблокировать запись, чтобы вы могли выполнять операторы против нее, вы можете выполнить эти операторы как транзакцию.

Чтобы выполнить SQL параллельно, вам нужно паралеллизировать вызовы SQL, выполняя ваш SQL из отдельных потоков / процессов в Java, C ++, perl или любом другом языке программирования (черт, запуск "isql" в сценарии оболочки в фоновом режиме будет работать)

1 голос
/ 19 мая 2015
0 голосов
/ 10 июня 2017

Задания агента SQL могут выполняться параллельно и создаваться непосредственно из TSQL.Ответ Ремуса Русану содержит ссылку, в которой упоминается об этом наряду с некоторыми недостатками.

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

Возможно запустить произвольный SQL от имени другого (более безопасного) пользователя, однако я считаю, что для назначения задания ему необходима привилегия sysadmin.

Возвращенный @pJobIdHexOut может использоваться для остановкиработа при необходимости.

create proc [Common].[usp_CreateExecuteOneTimeBackgroundJob] 
    @pJobNameKey          varchar(100),     -- Caller should ensure uniqueness to avoid a violation
    @pJobDescription      varchar(1000),
    @pSql                 nvarchar(max),
    @pJobIdHexOut         varchar(100) = null out, -- JobId as Hex string. For SqlServer 2014 binary(16) = varchar(64)
    @pDebug               bit = 0  -- True to include print messages
--
with execute as 'TSqlBackgroundJobOwner' -- requires special permissions (See below)
as
/*---------------------------------------------------------------------------------------------------------------------
    Purpose:  Create a one time background job and launch it immediately.  The job is owned by the "execute as" UserName 

              Caller must ensure the @pSql argument is safe.

Required Permissions for "execute as" user:

        -- User must be created with associated login (w/ deny connect).

        use [msdb];
        create user [$UserName$] for login [$LoginName$];
        alter role [SQLAgentUserRole] add member [$UserName$];
        alter role [SQLAgentReaderRole] add member [$UserName$];
        alter role [SQLAgentOperatorRole] add member [$UserName$];
        grant select on dbo.sysjobs to [$UserName$];
        grant select on dbo.sysjobactivity to [$UserName$];',

        use [Master];
        create user [$UserName$] for login [$LoginName$];
        grant execute on xp_sqlagent_is_starting to [$UserName$];
        grant execute on xp_sqlagent_notify to [$UserName$];';


    Modified    By           Description
    ----------  -----------  ------------------------------------------------------------------------------------------
    2014.08.22  crokusek     Initial version   
    2015.12.22  crokusek     Use the SP caller as the job owner (removed the explicit setting of the job owner).
  ---------------------------------------------------------------------------------------------------------------------*/
begin try       

    declare
        @usp                  varchar(100) = object_name(@@procid),
        @currentDatabase      nvarchar(100) = db_name(),
        @jobId                binary(16),        
        @jobOwnerLogin        nvarchar(100);

    set xact_abort on;    -- ensure transaction is aborted on non-catchables like client timeout, etc.
    begin transaction

        exec msdb.dbo.sp_add_job 
            @job_name=@pJobNameKey,
                @enabled=1, 
                @notify_level_eventlog=0, 
                @notify_level_email=2, 
                @notify_level_netsend=2, 
                @notify_level_page=2, 
                @delete_level=3, 
                @description=@pJobDescription,
                @category_name=N'Database Maintenance',
            -- If not overridden then the the current login is the job owner
            --@owner_login_name=@jobOwnerLogin,  -- Requires sysadmin to set this so avoiding.
            @job_id = @jobId output;

        -- Get the job_id string of the jobId (special format)
        --
        set @pJobIdHexOut = Common.ufn_JobIdFromHex(@jobId);

        if (@pDebug = 1)
        begin
            print 'JobId: ' + @pJobIdHexOut;
            print 'Sql: ' + @pSql;
        end

        exec msdb.dbo.sp_add_jobserver @job_id=@jobId; -- default is local server

        exec msdb.dbo.sp_add_jobstep 
            @job_id=@jobId, 
            @step_name=N'One-Time Job Step 1', 
                @step_id=1, 
            @command=@pSql,
                @database_name=@currentDatabase,
                @cmdexec_success_code=0, 
                @on_success_action=1, 
                @on_fail_action=2, 
                @retry_attempts=0, 
                @retry_interval=0, 
                @os_run_priority=0,
            @subsystem=N'TSQL', 
                @flags=0
            ;

          declare
              @startResult int;                    

          exec @startResult = msdb.dbo.sp_start_job 
              @job_id = @jobId;

      -- End the transaction
      --
      if (@startResult != 0)          
          raiserror('Unable to start the job', 16, 1);  -- causes rollback in catch block
      else
          commit;   -- Success

end try
begin catch
    declare        
        @CatchingUsp  varchar(100) = object_name(@@procid);    

    if (xact_state() = -1)
        rollback;

    --exec Common.usp_Log
    --    @pMethod = @CatchingUsp;

    --exec Common.usp_RethrowError
    --    @pCatchingMethod = @CatchingUsp;
end catch
0 голосов
/ 29 мая 2013

Если после прочтения всего выше о потенциальных проблемах, и вы все еще хотите запускать вещи параллельно, вы, вероятно, можете попробовать задания sql, поместить свои запросы в разные задания, а затем выполнить, вызвав задания, подобные этому

EXEC msdb..sp_start_job 'Job1'

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