Internet, UNIX, Video, Leisure…
Sybase database migration / reduction
One of the main problem of sybase (and other database) is the way it handle disk space. You must create « disk devices », which can be RAW or file on a filesystem. Then give some space of it to a database, and perhaps create or extend segments.
Of course, this may sound a good way to deal with it. Then comes the time when you need some storage for something else, or another database.
You start realizing that the 15 Gb you added to your database, thinking your data will grow as you reach your 1.000.000.000 subscriber… but your stalled at 150
So, using some sybase tools, you realize only 5% of the space is used. Then you wonder « how will I get the free space for something else ? »
The Sybase and Sybase support is simple : you can’t. But…
Of course you can. It’s only data after all. Your data.
The solution is simpler to say than to do : backup data and schema, drop the database, drop the devices, re-create the devices, the database then import.
One would say : eaaassssyyyyyy.
Then try to do it without using dump/load.
The fact is the dump/load Sybase command uses internal Sybase page structures. If you have a 15Gb database, even 5% filled, your dump will have a 15Gb size, minus the compression you set for the dump.
When loading, each page will be put in a page of the new database device. Meaning, you need to have a new database the same size as the old one. The load tool will tell you that if you are wrong.
And this is even worse than you may think : you need to have the same amount of data and log space (or more) !!
So… bcp out, then bcp in.
BCP is a command line tool provided by sybase. It load/unload data from/to a flat file.
First, get the schema out of the database.
For this I use the dbschema perl tool. Get it at http://www.midsomer.org
This is what I do :
mkdir DB1_schema
cd DB1_schema
/opt/monitor/perl/bin/perl /home/prune/dbschema/dbschema.pl -SDB1 -Usa -Ppassword -O1 -m -A -V -b --target-db my_new_db
You will get a directory per database inside DB1. In each directory you will have a file per type of object : table, stored procs, key, foreign key, view…
The use of « –target-db my_new_db » will create DBP in/out scripts with the right name to import data to a different database (my_new_db instead of my_old_db). See under for the BCP stuffs anyway.
Then, get the data out using bcp.
You need to bcp out the data each table at a time.
The database I’m using have almost a hundred tables. One solution is to use an option of the dbschema to create a bcp shell script. Or you can use the sp__bcp stored procedure from the awesom package you can find at http://www.edbarlow.com
sp__bcp need options so it can create the bcp command line :
- DSQUERY : the dataserver name
- database_name : the database to dump from
- sa : the login of the admin user or a user who can select every tables
- password : …
When creating the bcp in script, be sure to be in the right database you just have bcp out BUT put the database name where you will load the data, if different.
use my_old_db
go
sp__bcp "DB1", "my_old_db", "sa", "password", "out"
go
Also get the in script :
use my_old_db
go
sp__bcp "DB1", "my_new_db", "sa", "password", "in", "dat", "-b 10000"
go
This proc will not create any script. You need to copy the output to a file, make it executable.
The last parameter will split the load in chuck of 10000 lines, which will help to not fill the logs. Maybe 50000 or 100000 would be better. please comment.
Then you can create back your database on the right devices, with the right size, etc.
disk init
name = 'NewdbData',
physname = '/opt/db/dbdata/DB1_NewdbData',
vdevno = 7,
size = 2560000,
cntrltype = 0,
dsync = 'false'
go
disk init
name = 'NewdbLog',
physname = '/opt/db/dbdata/DB1_NewdbLog',
vdevno = 8,
size = 153600,
cntrltype = 0,
dsync = 'false'
go
CREATE DATABASE my_new_db ON NewdbData = 5000 LOG ON PhileasLog = 300
use master
go
sp_dboption phileas, 'single user', true
go
exec sp_logdevice phileas, PhileasLog
go
sp_dboption phileas, 'single user', false
go
You are ready to re-create the structure of the database. The « table structure » as Sybase support call it.
Go to the dbschema directory, in the db you want to create, and load the scripts one at a time, in the right order. Note that, if your developpers do fancy things in theire stored procs, the schema export from dbschema may not work. I had to use an extract from « CAST », then use dos2unix to translate some french accents to unix code.
Here is how I do it then :
dos2unix procs-cast.sql procs.sql
isql -Usa -w512 -SDB1 -Ppassword < defaults.sql > defaults.sql.err
isql -Usa -w512 -SDB1 -Ppassword < groups.sql > groups.sql.err
isql -Usa -w512 -SDB1 -Ppassword < types.sql > types.sql.err
isql -Usa -w512 -SDB1 -Ppassword < rules.sql > rules.sql.err
isql -Usa -w512 -SDB1 -Ppassword < tables.sql > tables.sql.err
isql -Usa -w512 -SDB1 -Ppassword < keys.sql > keys.sql.err
isql -Usa -w512 -SDB1 -Ppassword < views.sql > views.sql.err
isql -Usa -w512 -SDB1 -Ppassword < indexes.sql > indexes.sql.err
isql -Usa -w512 -SDB1 -Ppassword < fkeys.sql > fkeys.sql.err
isql -Usa -w512 -SDB1 -Ppassword < trigs.sql > trigs.sql.err
isql -Usa -w512 -SDB1 -Ppassword < procs.sql > procs.sql.err
Once this is done, just check you have all your stuffs :
select type, count(*) from sysobjects group by type
go
type
---- -----------
D 16 types
P 1072 procs
R 15 rule
RI 357 index
S 26 system tables
TR 538 trigger
U 555 table
V 94 view
You should have the same result as on your old database. In fact, I don’t ![]()
But the dev told me that it was normal. Some procs are « wrong » but they are never used on a history database, which is what I’m working on right now.
You can then load the data, using the bcp script.
If your files are big, you may fill the logs. You need to set a procedure to dump them. This proc will automaticaly be run by a trigger. You can add it in your database, or in sybsystemprocs. This proc is made for logging the dump, and dumping to a file. I just changed it to dump with « no_log », as we don’t care of the log during import.
Here is the proc :
CREATE PROC sp_thresholdaction (
@dbname varchar(30),
@segmentname varchar(30),
@space_left int,
@status int )
AS
BEGIN
declare @msg varchar(256),
@date_actuelle datetime,
@nom_fichier varchar(256),
@date_fichier varchar(20),
@rep_sauve_log varchar(40)
select @rep_sauve_log = 'compress::6::/DUMP_SYBASE/DB1/DumpDATA/'
select @date_actuelle = getdate()
select @date_fichier =
convert (char(8), @date_actuelle, 112) +'-'+
convert(varchar(2),datepart(hh,@date_actuelle)) +
convert(varchar(2),datepart(mi,@date_actuelle)) +
convert(varchar(2),datepart(ss,@date_actuelle))
select @nom_fichier = @rep_sauve_log + @dbname + @date_fichier + '.trn',
@msg = @date_fichier + ' Warning: dump transaction for ' + @dbname + ':' + @segmentname + ' (' + convert(varchar(12),@space_left) + ' free) on ' + @nom_fichier
print @msg
if @segmentname = 'logsegment'
dump tran @dbname with no_log
return
END
go
Finaly, run you bcp in script, and you are all set. I hope… ![]()
Don’t forget to change the DB owner and options, but if you are that far I’m sure you can do it.
18 décembre 2009 - 13:44
Hi,
sp_logdevice in your example is unnecessary (but will not hurt), it is used to separate log from existing mixed data/log databases. In your example you have already created your database with log separated from data…
Also, Ed Barlow stored procedure package is a good start to develop your own stored procedures. sp__bcp you mention is « incomplete »: it does not handles text/image columns (-T in bcp IN/OUT), identity columns (-E in bcp IN), timestamp columns and columns with default allowing NULL value…
Regards,
Auricom
18 décembre 2009 - 14:22
Many thanks for the precision.
I’m not working with Sybase database anymore, and have no way to test what you pointed out.
Whatever, we do use text, timestamp and NULL columns. We had no problem during the « migration », so…
I’m working with Oracle now.