Sybase Replication Server

Фильтр по тегу: sybase


Практическая задача- изменился тип или размерность некоторого поля

..а оно есть в нескольких таблицах. Таблиц много, куча связанных с ними журналов, за всеми так сразу не уследишь. Есть ли выход? Есть- при грамотном и разумном проектировании названия полей не повторяются. В любой момент можно узнать в каком реп деф у нас это поле подписано, сходу нарисовать альтер под него. Безусловно, не применять бездумно, а сначала оценить последствия и целесообразность.


--Д. Горчилин. Указывает репликационные дефинишены в которых есть данная колонка

---- простая версия:

declare @colnam varchar(30)
select @colnam='<<название поля>>'

select 'alter replication definition '+char(34)+objname+char(34)+' alter columns with '+char(34)+@colnam+char(34)+
' /*'+dsname+'.'+dbname+' --- '+rs_sites.name+' */' from rs_columns,rs_databases,rs_objects,rs_sites
where
rs_columns.objid=rs_objects.objid and
rs_databases.dbid=rs_objects.dbid and
rs_databases.prsid=rs_sites.id and
colname=@colnam

---------- сложная версия, указывает еще и существующий на данный момент тип

declare @colnam varchar(30)
select @colnam='<<название поля>>'

select 'alter replication definition '+char(34)+objname+char(34)+' alter columns with '+char(34)+@colnam+char(34)+
' /*'+rs_sites.name+' --->'+dsname+'.'+dbname+' '+
case when coltype=0 then 'char'
when coltype=1 then 'binary'
when coltype=4 then 'text'
when coltype=5 then 'image'
when coltype=6 then 'tinyint'
when coltype=7 then 'smallint'
when coltype=8 then 'int'
when coltype=9 then 'real'
when coltype=10 then 'float'
when coltype=11 then 'bit'
when coltype=12 then 'datetime'
when coltype=13 then 'smalldatetime'
when coltype=14 then 'money'
when coltype=15 then 'smallmoney'
when coltype=16 then 'numeric'
when coltype=17 then 'decimal'
when coltype=18 then 'varchar'
when coltype=19 then 'varbinary'
else '*' end +
case when coltype in(0,4,18) then '('+rtrim(convert(char(5),length))+')'
else ' ' end
+' */' from rs_columns,rs_databases,rs_objects,rs_sites
where
rs_columns.objid=rs_objects.objid and
rs_databases.dbid=rs_objects.dbid and
rs_databases.prsid=rs_sites.id and
colname=@colnam
order by rs_sites.name,dsname,dbname,objname


Рекомендации как всегда- сначала думать, потом делать. Иногда удачный альтер на лету валит систему, соблюдать осторожность. Второй момент, в новых версиях новые типы данных, увидали звездочку- творчески доработали :)
добавлено: 14 сен 15 просмотры: 1139, комментарии: 0



Практическая задача- добавить несколько таблиц в подписку

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


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

select * into #rs_databases from rs_databases
select * into #rs_sites from rs_sites

--declare @db_1 varchar (30),@db_2 varchar (30),@pubnam varchar(30)
--select @db_1 ='%1'
--select @db_2 ='%2'

select @pubnam= upper(rs_databases.dsname)+lower(rs_databases.dbname) +'_'+upper(#rs_databases.dsname)+lower(#rs_databases.dbname)
from rs_databases,#rs_databases where
rtrim(rs_databases.dsname)+'.'+rtrim(rs_databases.dbname) =@db_1 and
#rs_databases.dsname+'.'+#rs_databases.dbname =@db_2

select @db_1= rs_databases.dsname+'.'+rs_databases.dbname from rs_databases where rs_databases.dsname+'.'+rs_databases.dbname =@db_1
select @db_2= rs_databases.dsname+'.'+rs_databases.dbname from rs_databases where rs_databases.dsname+'.'+rs_databases.dbname =@db_2

--select @pubnam,@db_1,@db_2


select
'-- SUB: '+subname
from rs_subscriptions,rs_databases,#rs_databases where
rs_databases.dsname+'.'+rs_databases.dbname =@db_1 and
#rs_databases.dsname+'.'+#rs_databases.dbname =@db_2 and
rs_subscriptions.pdbid=rs_databases.dbid and
rs_subscriptions.dbid=#rs_databases.dbid
group by subname

select
--subname subid type objid dbid pdbid requestdate pownerid rownerid status recovering error_flag materializing dematerializing primary_sre replicate_sre materialization_try method generation parentid security mechanism prsid objname objid dbid objtype attributes ownertype crdate parentid ownerid rowtype phys_tablename deliver_as_name phys_objowner repl_objowner has_baserepdef minvers dsname dbname dbid dist_status src_status attributes errorclassid funcclassid prsid rowtype sorto_status ltype ptype ldbid enable_seq dsname dbname dbid dist_status src_status attributes errorclassid funcclassid prsid rowtype sorto_status ltype ptype ldbid enable_seq articlename articleid type primaryname primaryowner objid pubid requestdate
'-- TABLES: '+phys_tablename+char(9)+objname+char(9)+subname
from rs_subscriptions,rs_objects,rs_databases,#rs_databases,rs_articles where
rs_databases.dsname+'.'+rs_databases.dbname =@db_1 and
#rs_databases.dsname+'.'+#rs_databases.dbname =@db_2 and
--rs_subscriptions.objid=rs_objects.objid and
rs_subscriptions.pdbid=rs_databases.dbid and
rs_subscriptions.dbid=#rs_databases.dbid and
rs_articles.articleid=rs_subscriptions.objid and
rs_articles.objid=rs_objects.objid
order by phys_tablename

select '-- ['+rs_sites.name+'] '+@db_1+' ==> ['+#rs_sites.name+'] '+@db_2+ ' {'+@pubnam+'}'
from rs_databases,#rs_databases,rs_sites,#rs_sites where
rs_databases.dsname+'.'+rs_databases.dbname =@db_1 and
#rs_databases.dsname+'.'+#rs_databases.dbname =@db_2 and
rs_databases.prsid=rs_sites.id and
#rs_databases.prsid=#rs_sites.id


select 'create publication "'+@pubnam+'" with primary at '+@db_1,

char(10)+'create article "<<ARTICLE>>" for "'+@pubnam+'" with primary at '+@db_1+' with replication definition "<<REP DEF>>"',

char(10)+'validate publication "'+@pubnam+'" with primary at '+@db_1,

char(10)+'define subscription "'+@pubnam+'" for publication "'+@pubnam+'" with primary at '+@db_1+' with replicate at '+@db_2,

char(10)+'activate subscription "'+@pubnam+'" for publication "'+@pubnam+'" with primary at '+@db_1+' with replicate at '+@db_2

drop table #rs_databases
drop table #rs_sites

go
добавлено: 09 сен 15 просмотры: 1201, комментарии: 0



Как скриптом узнать размер очереди

Не всегда удобно проверять размер очереди централом. Иногда для мониторинга состояния лучше бы использовать свои скрипты. КАК установить размер очереди скриптом? Вот этим нехитным скриптом. Плюс он по ходу генерит заготовки для резюма коннекшенов. Важный момент- вармовские коннекшены здесь обрабатываются как бы не совсем адекватно, но это вызов для пытливых умов :)

select getdate ()
select 'ROUTE TO ->'+name,
'RSI',
count(*)
from rs_sites,rs_segments where
rs_sites.id=rs_segments.q_number
group by name
go

select dsname+'.'+dbname,
case when q_type=0 then 'dsi' else 'LTM' end,
count(*),
case when dist_status=1 then 'up' else '!!' end
from rs_databases,rs_segments where
rs_databases.dbid=rs_segments.q_number
group by dsname+'.'+dbname,
case when q_type=0 then 'dsi' else 'LTM' end,
case when dist_status=1 then 'up' else '!!' end
go
select '---------------------------- for resume ---------------------'
go
select 'resume connection to '+dsname+'.'+dbname+' skip transacion'+char(10)+'go'
from rs_databases
where
dist_status!=1 and src_status=1 and
prsid in (select id from rs_sites where name in (select charvalue from rs_config where optionname='oserver'))
group by 'resume connection to '+dsname+'.'+dbname+' skip transacion'+char(10)+'go'
go
добавлено: 06 сен 15 просмотры: 1165, комментарии: 0



Забавная подробность BCP

Были несколько раз забавные приключения, когда bcp паковала данные мимо форинкея. А потом у счастливых владельцев этих таблиц недоумение, раз даже на грани истерики. Судя по всему, ропот был услышан MS:



2005

https://technet.microsoft.com/ru-ru/library/ms186247(v=sql.90).aspx

По умолчанию, инструкция INSERT проверяет ограничения CHECK и FOREIGN KEY. Однако инструкция INSERT ... SELECT * FROM OPENROWSET(BULK...) позволяет переопределить проверку ограничений CHECK и FOREIGN KEY.

Примечание.

Нельзя отключить ограничения UNIQUE, PRIMARY KEY или NOT NULL.



2008 R2

https://technet.microsoft.com/ru-ru/library/ms186247(v=sql.105).aspx

Примечание

Только ограничения CHECK могут быть отключены. Нельзя отключить ограничения UNIQUE, PRIMARY KEY, FOREIGN KEY или NOT NULL.



То есть, в 2008 R2 проверку на форинкей отключить нельзя, а в 2005 можно.

Ну а в целом конечно форинкеи враг репликации. Таблицы иногда получают из разных источников, иногда возникают расхождения в данных. Упала репликация- за это голова болит вроде бы уже как и не у владельцев сервера- получателя. Лучше бы на стороне получателя убрать все проверки кроме PK. Это не всегда возможно, но очень желательно.
добавлено: 03 сен 15 просмотры: 1062, комментарии: 2



Практическая задача- сдуть очередь на полуживой сервер

Периодически возникала проблема- некий сервер помирает, его бы отписать, да накопившиеся в очереди транзакции не дают. В принципе, очередь можно просто сдуть. Но по ряду причин этот метод не всегда хорош, лучше бы оно отработало штатно. Еще один вариант- в базе побило несколько таблиц, транзакции по ним мешают. Именно по этим таблицам репликацию бы и отписать бы, но очередь не дает. Хочется сохранить очередь, выборочно удалив транзакции по некоторым таблицам. После их можно будет пересоздать, изменить структуру, закачать bcp. Иногда даже подкладывали вместо умершего сервера базу учебного сервера, и он быстренько сдувал очередь. Сделать то надо всего ничего- по таблицам идущим в эту базу создать пустой fsc, поднять. Репсервер честно все их применит- пустые. В базе при этом сами таблицы не нужны, достаточно репликационных объектов (вроде rs_lastcommit).
В литературе мне этот метод не встречался, но практически использовался часто.


/* Этот чудесный и замечательный скрипт позволяет сливать данные из очереди при полудохлой базе,
не выполняя каких-либо действий на sql-сервере и не очищая очередь силовыми методами*/

declare @dsname varchar(30),@dbname varchar(30)
select @dsname='%'
select @dbname='%'
select 'alter connection to "'+@dsname+'"."'+@dbname+'"'+char(10)+'set function string class to empty_function_class'

select 'create function string '+objname+
".rs_insert for empty_function_class with overwrite output language '/*empty*/'"+char(10)+'go',
char(10)+'create function string '+objname+
".rs_update for empty_function_class with overwrite output language '/*empty*/'"+char(10)+'go',
char(10)+'create function string '+objname+
".rs_delete for empty_function_class with overwrite output language '/*empty*/'"+char(10)+'go'
from rs_subscriptions,rs_objects,rs_articles,rs_databases
where rs_subscriptions.objid=rs_articles.articleid and
rs_articles.objid=rs_objects.objid and
rs_databases.dbid=rs_subscriptions.dbid and
dsname like @dsname and dbname like @dbname

select 'resume connection to "'+@dsname+'"."'+@dbname+'"'+char(10)+'go'
print 'Успехов и процветания, дорогой Дмитрий Ильич!'
добавлено: 02 сен 15 просмотры: 1022, комментарии: 0



Практическая задача- взвести флаги на репликацию

Прошло некоторое время, по ряду причин не связан какими-либо обязательствами. Решил выложить некоторые старые скрипты-примочки. Мелочь вроде, но иногда именно они приносят огромную пользу. Скрипты имеют важную особенность- написаны в виде учебных, избегал псевдонимов для лучшего понимания, некоторые из этих вещей делались в формате наглядного пособия. Кроме того, гуру SQL заметят некоторые моменты в плане стиля. Я это тоже вижу, себе я пишу иначе :) В принципе, любая серьезная работа подразумевает подготовку многих скриптов, не было большой работы в которой не пришлось бы придумывать что-то новое. Творческое это дело :)

/* Запусти меня в базе RSSD, и я расскажу какие таблицы ходят с конкретного сервера */
select 'DATABASE '+dsname+'.'+dbname+' tabename:'+phys_tablename
from rs_objects,rs_databases where rs_databases.dbid=rs_objects.dbid
and (phys_tablename not like 'rs_%%')
and dsname='ИмяСервера'
/*and dbname in('если надо- название базы')*/
group by dsname,dbname,phys_tablename
order by dsname,dbname,phys_tablename

/* Запусти меня в любой базе, и я сформирую скрипт, чтобы снести флаги на репликацию в этой базе */

select
'sp_setreptable '+name+' ,false'+char(13)+char(10)+'go'
from sysobjects where type='u'
order by name

/* Запусти меня в базе RSSD, и я сформирую скрипт, чтобы взвести флаги на репликацию для конкретного сервера */

select 'use '+dbname+char(10)+'go'+char(10)+'sp_setreptable '+phys_tablename+',true'+char(10)+'go'
from rs_objects,rs_databases where rs_databases.dbid=rs_objects.dbid
and (phys_tablename not like 'rs_%%') and dsname='ИмяСервера' /*!!!!!!!!!!!!!!!!*/

/* Запусти меня в базе RSSD, и я сформирую скрипт, чтобы взвести флаги на репликацию для конкретного сервера */
-- с группировкой и указанием имени сервера на котором полученный скрипт нужно запустить

select 'use '+dbname+' /* Run Me on: '+dsname+' */'+char(10)+'go'+char(10)+'sp_setreptable '+phys_tablename+',true'+char(10)+'go'
from rs_objects,rs_databases where rs_databases.dbid=rs_objects.dbid
and (phys_tablename not like 'rs_%%') and
--!!!
dsname='ИмяСервера' /*!!!!!!!!!!!!!!!!*/
--!!!
group by
'use '+dbname+' /* Run Me on: '+dsname+' */'+char(10)+'go'+char(10)+'sp_setreptable '+phys_tablename+',true'+char(10)+'go'


/* Запусти меня в базе RSSD, и я сформирую скрипт, чтобы взвести флаги на репликацию вообще для всех серверов */
-- с группировкой и указанием имени сервера на котором полученный скрипт нужно запустить

select 'use '+dbname+' /* Run Me on: '+dsname+' */'+char(10)+'go'+char(10)+'sp_setreptable '+phys_tablename+',true'+char(10)+'go'
from rs_objects,rs_databases where rs_databases.dbid=rs_objects.dbid
and (phys_tablename not like 'rs_%%') --and
--!!!
--dsname='ИмяСервера' /*!!!!!!!!!!!!!!!!*/
--!!!
group by
'use '+dbname+' /* Run Me on: '+dsname+' */'+char(10)+'go'+char(10)+'sp_setreptable '+phys_tablename+',true'+char(10)+'go'
order by dsname,dbname

/* Скрипт имени Горчилина */
--Dmitry Gorchilin scripts for Sybase Replication Server
добавлено: 01 сен 15 просмотры: 1012, комментарии: 0



Странная ошибка

ASE 15.5 RS 12.6

В чем ошибка- создана публикация, подписка. Данные НЕ идут.
Внешне все совершенно в порядке

Обнаружено сообщение в логе ASE, лтм все же ругался:

W. 2014/11/06 18:23:55. WARNING #32020 DIST(*** ###.###) - xec/dist.c(3002)
Table '%%%' is not defined.

Ситуация странная- флажок sp_setreptable взведен,
репликейшен дефинишен есть, публикация есть, подписка.
Но такое ощущение, что лтм не видит реп деф
Крутили по-всякому, вплоть до удаления и создания реп дефинишенов.
Не помогло.

А излечилось оно в конце концов очень просто:

sp_setreptable %%%,false
sp_setreptable %%%,true

Недоумеваю почему, но помогло
добавлено: 06 ноя 14 просмотры: 1540, комментарии: 0



Как дропнуть fsc при наличии роута

Удалить fsc- небольно и недолго, команда вроде

drop function string class <my_name>_function_class

Операция эта выполняется нечасто, выглядит нетривиально, очень помогает избавиться от неиспользуемых объектов.

Сегодня ожидал некоторый сюрприз, сообщение типа

Server Message: Number 15436, Severity 12
Server '****_RS', Line 0:
Inconsistency in RSSD table 'rs_repdbs'.

Много думал, решение оказалось простым и даже очевидным. Допустим, по роуту связаны сервера A_RS и B_RS
На A_RS создан FSC, он же назначен некоторым коннекшенам на этом сервере.
На сервере B_RS созданы некоторые объекты, которым этот FSC так же назначен. Так вот пока они существуют- удалить FSC невозможно. Сначала на B_RS нужно

drop function string ****.rs_insert for <my_name>_function_class --
drop function string ****.rs_update for <my_name>_function_class --
drop function string ****.rs_delete for <my_name>_function_class --

для всех таких объектов. И только после дропать, собственно, сам FSC

Server Message: Number 15116, Severity 0
Server '****_RS', Line 0:
Function string class '<my_name>_function_class' is dropped.

..и будет всем счастье :)
добавлено: 11 июн 14 просмотры: 1390, комментарии: 0



Каким образом на основании данных SQL сервера проверить работоспособность репликации

Коллеги иногда терзали серьезным вопросом- можно ли проверить состояние репликации в текущий момент?
Доступа к RepServer у них нет, средства мониторинга не всегда удобны.
При чем, разработчикам очень хотелось получить такую информацию из базы ASE сервера, доступ к этой информации желательно было обеспечить из приложения.

Логика оказалась достаточно проста:

ЭТО запускаем на rssd
/* Запусти меня в базе RSSD конкретного репсервера */
select
'insert into #databases values('+convert(char(3),dbid)+','+'"'+dsname+'.'+dbname+'"'+')'
from rs_databases


Полученный фрагмент вставляется в данный скрипт:
/* Запусти меня на той базе, куды чего-то реплицируется*/

create table #databases(dbid integer,dbname char(30))
print 'Да здравствует Дмитрий Горчилин!'

insert into #databases values(NNN,"SSS.BBB")
..

select
dbname,datediff (mi,origin_time,dest_commit_time),origin_time,dest_commit_time
from rs_lastcommit,#databases where dbid=origin
and abs(datediff (dd,getdate(),dest_commit_time))<10
and abs(datediff (dd,getdate(),origin_time))<10
order by datediff (mi,origin_time,dest_commit_time),dest_commit_time DESC

drop table #databases

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

Очень наглядно- видна ЗАДЕРЖКА с которой применяются транзакции.

И еще один момент- если данные не обновляются это не значит что все умерли. Иногда транзакции просто не образуются на источнике. По Фрейду- бывают и просто сны :)
добавлено: 18 мар 14 просмотры: 1383, комментарии: 0