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

Откуда:
Сообщений: 57
Если запрос SELECT читает сразу кучу таблиц, то как на них накладывается блокировка? Одновременно на все или как они понадобятся по его вразумению? Могут ли возникать дедлоки как бы внутри инструкции SELECT?
11 июл 13, 16:55    [14553840]     Ответить | Цитировать Сообщить модератору
 Re: Как накладывается блокировка  [new]
hertherherth
Guest
PZH,

шаред блокировка будет накладываться по мере встречи с данными
11 июл 13, 17:05    [14553908]     Ответить | Цитировать Сообщить модератору
 Re: Как накладывается блокировка  [new]
PZH
Member

Откуда:
Сообщений: 57
Т.е. дедлоки с процессами, которые лезут с U и X блокировками возможны.
11 июл 13, 17:34    [14554131]     Ответить | Цитировать Сообщить модератору
 Re: Как накладывается блокировка  [new]
Гавриленко Сергей Алексеевич
Member

Откуда:
Сообщений: 37254
PZH
Т.е. дедлоки с процессами, которые лезут с U и X блокировками возможны.
Естественно, потому что команда select может накладывать блокировки разной гранулярности и продолжительности.
11 июл 13, 17:40    [14554175]     Ответить | Цитировать Сообщить модератору
 Re: Как накладывается блокировка  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
PZH
Если запрос SELECT читает сразу кучу таблиц, то как на них накладывается блокировка? Одновременно на все или как они понадобятся по его вразумению? Могут ли возникать дедлоки как бы внутри инструкции SELECT?
План показывает как и в каком порядке.
Смысл зависит от уровня изоляции и структуры базы (FK и т.п.).

Read Committed - подразумевает что логическая целостность на всю логическую строку.
Т.е. локировки держатся сразу для всех строк связанных JOIN-ами и подобным образом.
При переходе к следующей строке (когда Loop и похожее) снимаются локировки с предыдущей и накладываются на следующую.

Для Serializable подразумевается что целостность не строковая, а транзакционная.

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

автор
шаред блокировка будет накладываться по мере встречи с данными
Ну, это не обязательно. Зависит от запроса. Может сразу всю таблу загребсти. Но это редкость. Чаще происходит эскалация от строк к страницам и далее к таблам.

PZH, главное понимать порядок. Важно что-бы порядок наложения в конкурентных задач был тот-же, а желательно не пересекался вообще. Если пересекается и тем более если есть блокировки, и 100% если дедлоки - то возможно, что структура системы была выбрана неверно.
12 июл 13, 16:18    [14559207]     Ответить | Цитировать Сообщить модератору
 Re: Как накладывается блокировка  [new]
Ivan Durak
Member

Откуда: Minsk!!!
Сообщений: 3754
Mnior
Read Committed - подразумевает что логическая целостность на всю логическую строку.
Т.е. локировки держатся сразу для всех строк связанных JOIN-ами и подобным образом.
При переходе к следующей строке (когда Loop и похожее) снимаются локировки с предыдущей и накладываются на следующую.

а если много таблиц джоинится последовательно, плюс подзапросы там на все таблицы сразу блокировка ??
12 июл 13, 16:30    [14559332]     Ответить | Цитировать Сообщить модератору
 Re: Как накладывается блокировка  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Ivan Durak
а если много таблиц джоинится последовательно, плюс подзапросы там на все таблицы сразу блокировка ??
Локировка не может быть сразу на всё. Локировка делается на конкретную одну строку/страницу в одной табле.
Несколько таблиц - несколько блокировок. Налагаются обычно также как указано в плане.

FROM Table1 JOIN Table2.
Если в плане сначала Table2, а далее loop join Table1, то сначала накладывается локировка на строку в Table2 вместе с её считыванием, далее Table1 с её считыванием, формируется итоговая строка результата, потом снимается с Table1 и с Table2 и так далее.

Единственное не скажу как снимается, перед началом считыванием следующей строки или во время. Для меня сейчас логично "во время".

Локировки разные бывают. Может налагаться на один ключ, может на целый диапазон. Зависит от условия запроса. Аля NOT Exists и условия типа > и <.
Это всё очевидно - согласно логики запроса.

И дофигища разных но. Ибо есть спулы, хеши, сортировки в планах.
По идее, если в плане в конце идёт сортировка, до кажись локировки уже все сняты.
Если спулы и хеши то тут локировки ставятся и не снимаются до "конца" для всех строк сразу.

А ну гусары, подтянулись! Где хранители тайных знаний?
Сергей Алексеевич вот не делится им. Тут ещё invm неподалёку тусовался.
12 июл 13, 18:37    [14560176]     Ответить | Цитировать Сообщить модератору
 Re: Как накладывается блокировка  [new]
Ivan Durak
Member

Откуда: Minsk!!!
Сообщений: 3754
автор
если в плане в конце идёт сортировка, до кажись локировки уже все сняты.
Если спулы и хеши то тут локировки ставятся и не снимаются до "конца" для всех строк сразу.

что-то не вижу разницы принципиальной между сортировкой и хэшем. Почему по-разному лочится должны?
12 июл 13, 22:32    [14560873]     Ответить | Цитировать Сообщить модератору
 Re: Как накладывается блокировка  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
Ivan Durak
автор
если в плане в конце идёт сортировка, до кажись локировки уже все сняты.
Если спулы и хеши то тут локировки ставятся и не снимаются до "конца" для всех строк сразу.
что-то не вижу разницы принципиальной между сортировкой и хэшем.
С сортировкой немного налажал в объяснении, она кажись всегда идёт сразу по мере поступления данных и перед ней не будет никаких аля спулов. Поэтому тут локировки могут сразу сниматься перед поступлением данных. Я говорю про сортировку "в конце", а не в середине плана. В середине плана это то что и хэш - смешивание потока данных.
Ivan Durak
Почему по-разному лочится должны?
Дайте покапитанить.
Хэш соединение состоит из 2х этапов:
- хэш строится по первой табле в плане, по всем её отобранным строкам, и т.к. связки ещё нет, то они все лочатся
- по мере поступления данных из второй таблы они там как обычно построчно лочатся и снимаются
По окончании строк во второй снимаются все локировки в первой, если хеш не используется повторно, естественно.

Кстати, есть много разных интерпретаторов и анализаторов планов. Но я не видел ни одного в котором говорится про "объём локировок".
Можно ведь на основании структуры и статистики плана сказать объём для каждого TIL. Ещё можно учитывать правила эскалации предсказывать их + статистика индексов - уточнять реальные объёмы.

И ещё, видел ли кто тулзы по предсказыванию дедлоков на основании поданных запросов/планов или по их выкусыванию из трассы?
А также вероятности блокировок по интенсивности запросов.
13 июл 13, 13:19    [14561856]     Ответить | Цитировать Сообщить модератору
 Re: Как накладывается блокировка  [new]
invm
Member

Откуда: Москва
Сообщений: 9836
Для интересующихся.

В процессе игр с XEvents родился наколенный тул по отслеживанию блокировок:
+
1. Для полноценной работы потребуется вот эта процедура, далее фигурирующая под именем dbo.clrspResultSetsToXML. В принципе можно и без нее, тогда не будет данных в столбце data результата. В нижеследующем скрипте ее вызов закомментирован.
2. Сам тул
set ansi_nulls, quoted_identifier on;
go

if schema_id('tlt') is null
 exec('create schema tlt;');

if typeproperty('tlt.ttDatabasePages', 'OwnerId') is null
 create type tlt.ttDatabasePages as table
 (
  database_id smallint not null,
  file_id smallint not null,
  page_num bigint not null,
  primary key (database_id, file_id, page_num)
 );

if object_id('tlt.vDatabasePageTypes', 'V') is not null
 drop view tlt.vDatabasePageTypes;
go
 
create view tlt.vDatabasePageTypes
as
select
 cast(t.page_type as tinyint) as page_type,
 t.page_type_desc
from
 (
  values
   (1, 'data'),
   (2, 'index'),
   (3, 'text mixed'),
   (4, 'text'),
   (7, 'sort'),
   (8, 'GAM'),
   (9, 'SGAM'),
   (10, 'IAM'),
   (11, 'PFS'),
   (13, 'boot'),
   (14, 'server configuration'),
   (15, 'file header'),
   (16, 'differential changed map'),
   (17, 'bulk change map')
 ) t(page_type, page_type_desc)
go

if object_id('tlt.fnLockResourceCracker', 'IF') is not null
 drop function tlt.fnLockResourceCracker;
go
 
create function tlt.fnLockResourceCracker
(
 @ResourceType sysname,
 @res0 bigint,
 @res1 bigint,
 @res2 bigint
)
returns table as
return (
 select
  case
   when @ResourceType in ('OBJECT', 'KEY') then cast(substring(cast(@res0 as binary(8)), 5, 4) as int)
  end as object_id,
  case
   when @ResourceType in ('KEY') then cast(substring(cast(@res1 as binary(8)), 7, 2) as int)
  end as index_id,
  case
   when @ResourceType in ('PAGE', 'EXTENT') then cast(@res1 as smallint) 
   when @ResourceType in ('RID') then cast(cast(right(cast(@res1 as binary(8)),2) as binary(2)) as smallint) 
  end as file_id,
  case
   when @ResourceType in ('PAGE', 'EXTENT', 'RID') then cast(@res0 as bigint) 
  end as page_num,
  case
   when @ResourceType in ('RID') then cast(cast(left(right(cast(@res1 as binary(8)),4), 2) as binary(2)) as smallint) 
  end as slot_num,
  case
   when @ResourceType in ('HOBT', 'KEY') then
    cast(
	 cast(right(cast(right(cast(@res1 as binary(8)),4) as binary(4)), 2) as binary(2)) +
	 cast(0x0000 as binary(2)) +
	 cast(right(cast(right(cast(@res0 as binary(8)),4) as binary(4)), 2) as binary(2)) +
	 cast(left(cast(right(cast(@res0 as binary(8)),4) as binary(4)), 2) as binary(2))
	as bigint)
  end as partition_id,
  case
   when @ResourceType in ('KEY') then
	'(' + lower(convert(varchar(30),
	       cast(substring(cast(@res1 as binary(8)), 6, 1) as binary(1)) +
           cast(substring(cast(@res1 as binary(8)), 5, 1) as binary(1)) +
           cast(substring(cast(@res2 as binary(8)),8, 1) as binary(1)) +
           cast(substring(cast(@res2 as binary(8)),7, 1) as binary(1)) +
           cast(substring(cast(@res2 as binary(8)),6, 1) as binary(1)) +
           cast(substring(cast(@res2 as binary(8)),5, 1) as binary(1))
   , 2)) + ')' 
  end as lock_resource
);
go

if object_id('tlt.spGetDatabasePagesInfo', 'P') is not null
 drop procedure tlt.spGetDatabasePagesInfo;
go

create procedure tlt.spGetDatabasePagesInfo
 @pages tlt.ttDatabasePages readonly,
 @result xml output
as
begin
 set nocount on;
 
 declare @s varchar(max), @database_id smallint, @file_id smallint, @page_num bigint, @x xml, @pd xml;
 
 declare @p table (ParentObject nvarchar(255), Object nvarchar(255), Field nvarchar(255), VALUE nvarchar(255));
 declare @r table (database_id smallint, file_id smallint, page_num bigint, page_type tinyint, object_id int, index_id int, page_data xml);
 
 declare p cursor local fast_forward for
  select
   database_id, file_id, page_num
  from
   @pages;
 
 open p;
 fetch next from p into @database_id, @file_id, @page_num;
 while @@fetch_status = 0
  begin
   select
    @s = 'dbcc page(' + cast(@database_id as varchar(10)) + ', ' + cast(@file_id as varchar(10)) + ', ' + cast(@page_num as varchar(30)) + ', 3) with no_infomsgs, tableresults';
/*
   begin try
    exec dbo.clrspResultSetsToXML @s, @x output;
   end try
   begin catch
    select
     @x = null;
   end catch;
*/
   delete from @p;
   
   with x as
   (
    select
     n.value('(ParentObject)[1]', 'varchar(255)') as ParentObject,
     n.value('(Object)[1]', 'varchar(255)') as Object,
     n.value('(Field)[1]', 'varchar(255)') as Field,
     n.value('(VALUE)[1]', 'varchar(255)') as VALUE
    from
     @x.nodes('/resultset[1]/data/row') t(n)
   )
   insert into @p
    (ParentObject, object, Field, VALUE)
   select
    ParentObject, object, Field, value
   from
    x;
    
   select
    @pd = @x.query('resultset[2]/data')
   where
    exists(select 1 from @p where Field = 'm_type' and VALUE = '2'/*index page*/);

   if @@rowcount = 0
    with d as
    (
     select
      substring(ParentObject, ss.v, se.v - ss.v) as slot,
      Field as column_name,
      value as column_value
     from
      @p p cross apply
      (select patindex('%[0-9]%', p.ParentObject)) ss(v) cross apply
      (select charindex(' ', p.ParentObject, ss.v)) se(v)
     where
      exists(select 1 from @p where Field = 'm_type' and VALUE = '1'/*data page*/) and
      p.ParentObject like 'Slot [0-9]%' and
      p.Object like 'Slot [0-9]%'
    ),
    s as
    (
     select distinct
      slot
     from
      d
    )
    select
     @pd = (
      select
       slot as [@slot],
       dc.column_values as [*]
      from
       s cross apply
       (select (select column_name, column_value from d where slot = s.slot for xml path(''), type) as column_values) dc
      for xml path('row'), root('data'), type
     );
    
   insert into @r
    (database_id, file_id, page_num, page_type, object_id, index_id, page_data)
   select
    @database_id, @file_id, @page_num,
    min(cast(case when Field = 'm_type' then VALUE end as tinyint)) as page_type,
    min(cast(case when Field = 'Metadata: ObjectId' then VALUE end as int)) as object_id,
    min(cast(case when Field = 'Metadata: IndexId' then VALUE end as int)) as index_id,
    @pd
   from
    @p
   where
    ParentObject = 'PAGE HEADER:' and
    Field in ('Metadata: ObjectId', 'Metadata: IndexId', 'm_type');

   fetch next from p into @database_id, @file_id, @page_num;
  end;
 close p;
 deallocate p;

 select
  @result = (
   select
    database_id, file_id, page_num, page_type, object_id, index_id, page_data
   from
    @r
   for xml path('page_info'), type
  );
  
 return 0;
end;
go

if object_id('tlt.fnGetDatabasePageInfoAsTable', 'IF') is not null
 drop function tlt.fnGetDatabasePageInfoAsTable;
go

create function tlt.fnGetDatabasePageInfoAsTable
(
 @x xml
)
returns table
as
return (
 select
  n.value('database_id[1]', 'smallint') as database_id,
  n.value('file_id[1]', 'smallint') as file_id,
  n.value('page_num[1]', 'bigint') as page_num,
  n.value('page_type[1]', 'tinyint') as page_type,
  n.value('object_id[1]', 'int') as object_id,
  n.value('index_id[1]', 'int') as index_id,
  n.query('page_data[1]') as page_data
 from
  @x.nodes('page_info') t(n)
);
go

if object_id('tlt.spStartTrackingLocks', 'P') is not null
 drop procedure tlt.spStartTrackingLocks;
go

create procedure tlt.spStartTrackingLocks
as
begin
 set nocount on;
 set transaction isolation level read committed;

 declare @s varchar(max), @event_session sysname;

 if object_id('tempdb..##TLEventSessions', 'U') is null 
  create table ##TLEventSessions
  (
   spid int not null primary key,
   event_session sysname
  );

 select
  @event_session = event_session
 from
  ##TLEventSessions
 where
  spid = @@spid;

 if @@rowcount > 0
  begin
   select @s = 'drop event session ' + quotename(@event_session) + ' on server;';
   if exists(select 1 from sys.server_event_sessions where name = @event_session)
    exec(@s);
  end;

 select
  @event_session = cast(newid() as varchar(36));
 
 with s as
 (
  select
   @@spid as spid,
   @event_session as event_session
 )
 merge into ##TLEventSessions t
 using s on s.spid = t.spid
 when not matched then
  insert (spid, event_session) values (s.spid, s.event_session)
 when matched then
  update
   set event_session = s.event_session;

 select @s = 'drop event session ' + quotename(@event_session) + ' on server;';
 if exists(select 1 from sys.server_event_sessions where name = @event_session)
  exec(@s);

 select @s =
  'create event session ' + quotename(@event_session) + ' on server
   add event sqlserver.lock_acquired
    (
     where sqlserver.session_id = ' + cast(@@spid as varchar(10)) +
  ' ),
   add event sqlserver.lock_released
    (
     where sqlserver.session_id = ' + cast(@@spid as varchar(10)) +
  ' )
   add target package0.ring_buffer
   (
    set max_memory = 4096
   )
   with (max_dispatch_latency = 1 seconds, track_causality = on);'

 exec(@s);

 select @s = 'alter event session ' + quotename(@event_session) + ' on server state = start;';
 exec(@s);

 return 0;
end;
go

if object_id('tlt.spStopTrackingLocks', 'P') is not null
 drop procedure tlt.spStopTrackingLocks;
go

create procedure tlt.spStopTrackingLocks
 @event_session sysname output,
 @DatabaseList nvarchar(max) = null,
 @IncludePageData bit = 0
 
as
begin
 set nocount on;
 set transaction isolation level read committed;

 waitfor delay '00:00:02';

 declare @s varchar(max), @x xml, @p tlt.ttDatabasePages, @hdoc int;

 select
  @event_session = event_session
 from
  ##TLEventSessions
 where
  spid = @@spid;

 if @@rowcount = 0
  return 0;

 select
  @x = cast(dt.target_data as xml)
 from
  sys.dm_xe_session_targets dt join
  sys.dm_xe_sessions ds on ds.Address = dt.event_session_address
  where
   dt.target_name = 'ring_buffer' and
   ds.Name = @event_session;
 
 select @s = 'alter event session ' + quotename(@event_session) + ' on server state = stop;';
 exec(@s);

 select @s = 'drop event session ' + quotename(@event_session) + ' on server;';
 if exists(select 1 from sys.server_event_sessions where name = @event_session)
  exec(@s);

 exec sp_xml_preparedocument @hdoc output, @x;

 declare @raw_data table
 (
  id int identity(1, 1), activity_id varchar(50), activity_sequence int, event_name varchar(255), resource_type varchar(30),
  lock_mode varchar(30), owner_type varchar(30), transaction_id bigint, database_id smallint,
  resource_0 bigint, resource_1 bigint, resource_2 bigint
 );
 
 insert into @raw_data
 (
  activity_id, activity_sequence, event_name, resource_type, lock_mode, owner_type, transaction_id, database_id,
  resource_0, resource_1, resource_2
 )
 select
  activity_id,
  cast(reverse(left(reverse(activity_id), charindex('-', reverse(activity_id)) - 1)) as int) as activity_sequence,
  min(event_name) as event_name,
  min(case when name = 'resource_type' then [text] end) as resource_type,
  min(case when name = 'mode' then [text] end) as lock_mode,
  min(case when name = 'owner_type' then [text] end) as owner_type,
  min(case when name = 'transaction_id' then cast(value as bigint) end) as transaction_id,
  min(case when name = 'database_id' then cast(value as smallint) end) as database_id,
  min(case when name = 'resource_0' then cast(value as bigint) end) as resource_0,
  min(case when name = 'resource_1' then cast(value as bigint) end) as resource_1,
  min(case when name = 'resource_2' then cast(value as bigint) end) as resource_2
 from
  openxml(@hdoc, '/RingBufferTarget/event/data', 2)
  with (
   event_name varchar(255) '../@name',
   name varchar(255) '@name',
   value varchar(255) './value',
   [text] varchar(255) './text',
   activity_id varchar(50) '../action/value' 
  )
 group by
  activity_id
 order by
  activity_sequence;

 exec sp_xml_removedocument @hdoc;

 declare @t table
 (
  id int identity, event_name varchar(255), resource_type varchar(30), lock_mode varchar(30),
  database_id smallint, object_id int, index_id int, file_id smallint, page_num bigint, slot_num smallint,
  partition_id bigint, lock_resource varchar(50), activity_id varchar(50), activity_secuence int
 );
 
 insert into @t
 (
  event_name, resource_type, lock_mode, database_id, object_id, index_id, file_id, page_num, slot_num,
  partition_id, lock_resource, activity_id, activity_secuence
 )
 select
  x.event_name,
  x.resource_type,
  x.lock_mode,
  x.database_id,
  r.object_id,
  r.index_id,
  r.file_id,
  r.page_num,
  r.slot_num,
  r.partition_id,
  r.lock_resource,
  x.activity_id,
  x.activity_sequence
 from
  @raw_data x outer apply
  tlt.fnLockResourceCracker(x.resource_type, x.resource_0, x.resource_1, x.resource_2) r
 where
  @DatabaseList is null or
  ',' + @DatabaseList + ',' like '%,' + db_name(x.database_id) + ',%'
 order by
  x.id;

 insert into @p
  select distinct
   database_id, file_id, page_num
  from
   @t
  where
   page_num is not null;

 if object_id('tempdb..##TLResult', 'U') is null
  begin
   create table ##TLResult
   (
    tlr_id int identity, event_name varchar(255), resource_type varchar(30), lock_mode varchar(30),
    lock_resource varchar(50), database_id smallint, file_id smallint, page_num bigint, slot_num smallint, page_type tinyint,
    page_type_desc varchar(50), object_id int, index_id int, database_name sysname null, schema_name sysname null, object_name sysname null, index_name sysname null,
    data xml, event_session sysname,
    primary key (tlr_id)
   );

   create index [IX_##TLR__event_session] on ##TLResult (event_session);
  end;

 insert into ##TLResult
  (
   event_name, resource_type, lock_mode, lock_resource,
   database_id, file_id, page_num, slot_num, page_type, page_type_desc,
   object_id, index_id, database_name, schema_name, object_name, index_name,
   data, event_session
  )
 select
  t.event_name, t.resource_type, t.lock_mode, t.lock_resource,
  t.database_id, t.file_id, t.page_num, t.slot_num, p.page_type, pt.page_type_desc,
  oi.object_id, oi.index_id, db_name(t.database_id), object_schema_name(oi.object_id, t.database_id), object_name(oi.object_id, t.database_id), i.name,
  case when @IncludePageData = 1 and t.resource_type = 'PAGE' then p.page_data else d.data end, @event_session
 from
  @t t left join
  tlt.fnGetDatabasePageInfoAsTable(@x) p on p.database_id = t.database_id and p.file_id = t.file_id and p.page_num = t.page_num left join
  tlt.vDatabasePageTypes pt on pt.page_type = p.page_type left join
  sys.partitions sp on t.database_id = db_id() and sp.partition_id = t.partition_id cross apply
  (select coalesce(sp.object_id, p.object_id, t.object_id) as object_id, coalesce(sp.index_id, p.index_id, t.index_id) as index_id) oi left join
  sys.indexes i on t.database_id = db_id() and i.object_id = oi.object_id and i.index_id = oi.index_id outer apply
  (
   select
    pd.n.query('.') as data
   from
    tlt.fnGetDatabasePageInfoAsTable(@x) a cross apply
    a.page_data.nodes(
     '/page_data/data/row[
       (column_name = "KeyHashValue" and column_value = sql:column("t.lock_resource")) or
       @slot = sql:column("t.slot_num") or
       KeyHashValue = sql:column("t.lock_resource")
      ]'
    ) pd(n)
   where
    a.database_id = t.database_id and object_id = oi.object_id and
    (
     (t.resource_type = 'KEY' and oi.index_id = a.index_id) or
     (t.resource_type = 'RID' and pt.page_type_desc = 'data')
    )
  ) d
 order by
  t.id;

end;
go

Пример использования:
create table dbo.Table1 (t1_id int primary key, v1 int unique);
create table dbo.Table2 (t2_id int primary key, v2 int references dbo.Table1 (v1));

insert into dbo.Table1
values
 (1, 1), (2, 3), (3, 4);

insert into dbo.Table2
values
 (1, 1), (2, 3);

exec tlt.spStartTrackingLocks;
go

update dbo.Table2
set
 v2 = 3
where
 t2_id = 1;
go

declare @event_session sysname, @db sysname = db_name();

exec tlt.spStopTrackingLocks @event_session output, @db;

select
 *
from
 ##TLResult
where
 event_session = @event_session and 
 (object_id in (object_id('dbo.Table1', 'U'), object_id('dbo.Table2', 'U')) or resource_type = 'PAGE')
order by
 tlr_id;
go

drop table dbo.Table2, dbo.Table1;
go
Результат:
Картинка с другого сайта.

ЗЫ: Следует помнить, что данные со страниц читаются постфактум и могут не соответствовать таковым на начало трассы.
15 июл 13, 12:08    [14566598]     Ответить | Цитировать Сообщить модератору
 Re: Как накладывается блокировка  [new]
Mnior
Member

Откуда: Кишинёв
Сообщений: 6724
invm, не хватает PS в конце поста - куда слать пожертвования.
Кропотливый труд должен оплачиваться. Чем больше спец тем меньше должен зависеть от работодателя.
А то современная тенденция холопства убивает всякий энтузиазм развития этого грёбаного мирка. IMXO
16 июл 13, 18:18    [14574837]     Ответить | Цитировать Сообщить модератору
Все форумы / Microsoft SQL Server Ответить