1. Préambule▲
Sybase Adaptive Server offre un éventail d'utilitaires permettant de tester l'intégrité physique d'une base de données : les fameux dbcc. Il existe une kyrielle de dbcc :
- checkalloc ;
- checkdb ;
- checktable ;
- checkverify ;
- indexalloc ;
- rebuild_text ;
- reindex ;
- tablealloc.
… sans compter ceux, nombreux et non documentés. Tous souffrent de la même carence :
- ils sont en mesure d'analyser une base en ligne ;
- en ligne, ils ne peuvent corriger les erreurs ;
- en multiutilisateur, ils relèvent parfois des erreurs qui n'en sont pas (spurious error) puisque l'état d'un bloc de données peut être modifié pendant l'analyse ;
- l'analyse des rapports générés est fastidieuse et compliquée.
Depuis sa version 11.5, Sybase Adaptive Server fournit un puissant outil permettant de contrôler rapidement et en ligne l'intégrité des bases de données. Il répond au doux nom de dbcc checktorge.
Il s'oppose aux autres DBCC, car il se repose sur un référentiel qui lui permet
- de gérer le cas des erreurs inconsistantes ;
- d'offrir des rapports de meilleure facture, mis en forme par des procédures stockées idoines ;
- de ne pas parasiter les performances de la base de production analysée.
Ces avantages ont malheureusement un prix : le processus d'installation et de configuration de la base référentielle dbccdb est lourd est fastidieux. Nombre de DBA Sybase n'utilisent donc pas cet outil puissant par méconnaissance ou en étant rebuté par la phase d'installation et de configuration.
La procédure qui suit a comme but de vous guider dans l'installation de la dbccdb et de vous offrir des outils qui vous permettront de la gérer aisément.
2. Installation de dbccdb▲
Première chose à faire, créer une base dbccdb. Afin que celle-ci impacte le moins possible sur les autres devices, je vous conseille de la créer sur deux devices bien spécifiques : La commande suivante vous permet de déterminer quelles sont les volumétries attendues pour dbccdb.
use
master
exec
sp_plan_dbccdb
Riche de ces valeurs créez ensuite votre base:
create
database
dbccdb on
dbccdb_data01=
100M log
on
dbccdb_log01=
10M
Exécutez ensuite le script suivant
- sous Windows: %SYBASE%\%SYBASE_ASE%\scripts\installdbccdb ;
- sous Unix: $SYBASE/$SYBASE_ASE/scripts/installdbccdb.
Allez ensuite dans la base dbccdb, créez la procédure stockée sp_dbcc_init. Lors de son premier appel, cette procédure configure toutes les DBs afin qu'elles puissent utiliser dbcc checkstorage Lors des appels suivants, elle reconfigure les paramètres pour qu'ils répondent aux critères de sp_dbcc_evaluatedb
create
procedure
sp_dbcc_init (
@cache
varchar
(
30
)
=
NULL
)
/*
* Auteur : Fabien Celaia
* Date : 23.1.2002
* Certif. : ASE 12.5 (sinon quelques changements de paramètres nécessitent un reboot)
* Préreq. : 1) dbccdb est créée
* 2) Script installdbccdb déjà exécuté
* Desc. : 1) Premier appel : configure toutes les DBs afin qu'elles puissent utiliser dbcc checkstorage
* 2) Ensuite : reconfigure les paramètres pour qu'ils répondent aux critères de sp_dbcc_evaluatedb
* Syntaxe : exec dbccdb..sp_dbcc_init
* Param : Entrée : -
* Sortie : -
*/
as
begin
declare
@max_text int
declare
@max_wt int
declare
@max_cache int
declare
@dev_name varchar
(
30
)
declare
@dbid smallint
, @dbid1 smallint
, @dbid2 smallint
declare
@scanws_size int
declare
@textws_size int
declare
@cache_size int
declare
@wt_count smallint
declare
@dbname varchar
(
30
)
declare
@dbcc_dbname varchar
(
30
)
declare
@size float
declare
@msg varchar
(
1024
)
declare
@min_wssize int
/* taille maximale du workspace */
declare
@new_min_wssize int
/* contrôle la taille minimum du workspace */
declare
@min_cachesize int
/* Taille minimale du cache */
declare
@err int
/*
** ces variables sont utiles au formatage de l'output
*/
declare
@str1 varchar
(
30
)
declare
@tws varchar
(
30
)
declare
@sws varchar
(
30
)
/*
** Empêche l'utilisation de cette proc dans une transaction puisque des tables temporaires sont créées
*/
if
@@trancount >
0
begin
/*
** 17260, "Ne pas utiliser %1! dans une transaction ouverte."
*/
raiserror 17260
, "sp_plan_dbccdb"
return
(
1
)
end
else
begin
set
chained off
end
set
transaction
isolation
level
1
set
nocount on
/*
** Création de la table temporaire stockant les résultats et déclaration d'un curseur
*/
create
table
#dbcc_dblist(dbid int, ldev_name varchar(30))
declare
cursor_dbcc_dblist cursor
for
select
dbid from
#dbcc_dblist
/*
** ajout de dbname et dbid pour toutes les bases valides de #dbcc_dblist, à l'exception de model et tempdb
*/
insert
#dbcc_dblist(dbid, ldev_name)
select
distinct
su.dbid, dev.name
from
master
..sysdevices dev, master
..sysusages su
where
dev.cntrltype =
0
and
su.vstart between
dev.low and
dev.high
and
dbid between
3
and
31000
/*
** Taille minimum de workspace à 24 pages
*/
select
@min_wssize =
24
/*
** Création de la table temporaire permettant de stocker les informations de la configuration
*/
create
table
#dbcc_config(dbid int, dbname varchar(30) null,
scanws_size int
null
, textws_size int
null
,
wt_count smallint
null
, cache_size int
null
)
declare
cursor_dbcc_config cursor
for
select
dbname, scanws_size, textws_size, wt_count, cache_size
from
#dbcc_config
/*
** Pour chaque dbid de la table #dbcc_dblist, calcul de ses paramètres de configuration
*/
open
cursor_dbcc_dblist
fetch
cursor_dbcc_dblist into
@dbid
while
(
@@sqlstatus =
0
)
begin
/*
** Récupère le nom de la base
*/
select
@dbname =
db_name(
@dbid)
/*
** Contrôle su le nom de la base est déjà présent.
** Si tel est le cas, continue avec la prochaine entrée. La table #dbcc_dblist
** peut avoir plusieurs lignes pour une base donnée si cette base réside sur
** plusieurs devices. Le calcul n'est utile qu'une seule fois cependant.
*/
if
exists
(
select
*
from
#dbcc_config where dbid = @dbid)
begin
fetch
cursor_dbcc_dblist into
@dbid
continue
end
/*
** Calcul le nombre de devices impactés par cette base
** Détermine le nombre de worker processes basés sur ce nombre
*/
select
@wt_count =
count
(*)
from
#dbcc_dblist
where
#dbcc_dblist.dbid = @dbid
if
(
@wt_count <
1
)
select
@wt_count =
1
else
if
(
@wt_count >
128
)
select
@wt_count =
128
/*
** Taille minimale du cache de 640K * @wt_count
*/
select
@min_cachesize =
640
*
@wt_count
/*
** La taille minimum du workspace dépend aussi du nombre de worker
** processes. Ajustement de la valeur.
*/
select
@new_min_wssize =
((
@wt_count +
1
)
*
8
)
if
(
@new_min_wssize <
@min_wssize)
select
@new_min_wssize =
@min_wssize
/*
** Calcul de la taille du workspace scanws pour cette base, qui équivaut au 1.2%
** de la taille de la base. Unité : la page
*/
select
@scanws_size =
ceiling
(
sum
(
size)
*
0
.012
)
from
master
..sysusages
where
dbid =
@dbid
/*
** Arrondi au multiple de 8 supérieur (unité d'allocation = 1 extent = 8 pages)
*/
select
@scanws_size =
((
@scanws_size /
8
)
+
1
)
*
8
/*
** Taille le workspace texte au 25% du workspace scan et l'arrondit au multiple de 8
*/
select
@textws_size =
ceiling
(
@scanws_size *
0
.25
)
select
@textws_size =
((
@textws_size /
8
)
+
1
)
*
8
/*
** La taille minimum requise pour les workspaces et de @new_min_wssize pages.
*/
if
(
@scanws_size <
@new_min_wssize)
begin
select
@scanws_size =
@new_min_wssize
end
if
(
@textws_size <
@new_min_wssize)
begin
select
@textws_size =
@new_min_wssize
end
/*
** Pour les petites bases (< 20MB), augmentation de la taille du
** scanws de 8 pages, checkstorage utilisant un extent plein pour
** le mapping des pages. 1.2 % de la taille d'une petite base ne
** pourrait suffire.
*/
if
(
@scanws_size <=
128
)
select
@scanws_size =
@scanws_size +
8
/*
** conversion de la taille des workspaces en Ko
*/
select
@scanws_size =
@scanws_size *
@@maxpagesize /
1024
select
@textws_size =
@textws_size *
@@maxpagesize /
1024
/*
** Dimensionne la taille du cache à 20% de la taille des workspaces.
** La taille du cache est actuellement la taille du buffr pool de 16K.
** La taille doit être de @cache_size + 512K
*/
select
@cache_size =
ceiling
((
@scanws_size +
@textws_size)
*
0
.2
)
if
(
@cache_size <
@min_cachesize)
begin
select
@cache_size =
@min_cachesize
end
/*
** Insertion des valeurs calculées pour cette base dans la table
** #dbcc_config table. Cette table est utilisée à la génération d'un rapport
*/
insert
into
#dbcc_config(dbid, dbname, scanws_size, textws_size,
wt_count, cache_size)
values
(
@dbid, @dbname, @scanws_size, @textws_size,
@wt_count, @cache_size)
fetch
cursor_dbcc_dblist into
@dbid
end
close
cursor_dbcc_dblist
print
""
/*
** Calcule (en Mo) la taille de la base dbccdb. Même si checkstorage
** peut être exécuté en parallèle sur plusieurs bases,
** il est peu vraisemblable et pas recommandé de scanner plus de deux bases.
** Déterminons donc la taille en nous basant sur les deux plus grosses bases.
*/
select
@dbid1 =
dbid from
#dbcc_config
group
by
dbid having
sum
(
scanws_size)
=
max
(
sum
(
scanws_size))
select
@dbid2 =
dbid from
#dbcc_config where dbid != @dbid1
group
by
dbid having
sum
(
scanws_size)
=
max
(
sum
(
scanws_size))
select
@size =
(
sum
(
scanws_size)
+
sum
(
textws_size))
from
#dbcc_config
where
dbid =
@dbid1 or
dbid =
@dbid2
/* Retour des valeurs de configuration */
select
@max_wt=
max
(
wt_count)
,
@max_cache=
max
(
cache_size)
from
#dbcc_config
/* Le premier paramètre est le nom du cache. S'il n'est pas renseigné, nous
* prendrons soit le premier cache contenant "%dbcc%" soit "default data cache"
*/
if
@cache
is
null
select
@cache
=
name
from
master
..sysconfigures
where
name
like
"%dbcc%"
and
parent =
19
if
@cache
is
null
select
@cache
=
"Default data cache"
/* Population du cache */
create
table
#cache
(
caches varchar
(
30
)
not
null
,
POOL2K int
null
,
POOL16K int
null
)
insert
into
#cache
select
convert
(
varchar
(
30
)
, comment
)
, null
, null
from
master
..syscurconfigs
where
config =
19
and
comment
!=
"0"
update
#cache set POOL2K = s.value
from
#cache c, master..syscurconfigs s
where
s.config =
22
and
c.caches =
s.comment
update
#cache set POOL16K = s.value
from
#cache c, master..syscurconfigs s
where
s.config =
24
and
c.caches =
s.comment
select
@str1=
convert
(
varchar
(
30
)
,@max_cache)+
"K"
exec
sp_poolconfig @cache
, @str1 ,"16K"
/* Configuration des worker processes */
select
@wt_count =
value
from
master
..sysconfigures where
name
=
"number of worker processes"
if
@wt_count <
@max_wt
exec
sp_configure "number of worker processes"
, @max_wt
/* Adjonction des 2 segments nécessaires */
select
@dev_name=
name
from
master
..sysdevices,
master
..sysusages
where
dbid=
db_id(
"dbccdb"
)
and
vstart between
low and
high
and
segmap !=
4
if
not
exists
(
select
*
from
dbccdb..syssegments where
name
=
"scan_seg"
)
exec
dbccdb..sp_addsegment scan_seg, dbccdb, @dev_name
if
not
exists
(
select
*
from
dbccdb..syssegments where
name
=
"text_seg"
)
exec
dbccdb..sp_addsegment text_seg, dbccdb, @dev_name
/* Configuration pour chaque base utilisateur (il s'agit là aussi d'un choix: vous pouvez ajouter les bases système aussi) */
open
cursor_dbcc_config
fetch
cursor_dbcc_config into
@dbname, @scanws_size, @textws_size, @wt_count, @cache_size
while
(
@@sqlstatus !=
2
)
begin
/* Création des Workspaces*/
select
@str1=
convert
(
varchar
(
30
)
, @scanws_size)+
"K"
,
@sws=
@dbname+
"_scan_ws"
if
not
exists
(
select
*
from
dbccdb..sysobjects where
name
=
@sws and
type
=
"U"
)
exec
dbccdb..sp_dbcc_createws dbccdb, scan_seg, @sws,"scan"
, @str1
select
@str1=
convert
(
varchar
(
30
)
, @textws_size)+
"K"
,
@tws=
@dbname+
"_text_ws"
if
not
exists
(
select
*
from
dbccdb..sysobjects where
name
=
@tws and
type
=
"U"
)
exec
dbccdb..sp_dbcc_createws dbccdb, text_seg, @tws,"text"
, @str1
select
@str1=
convert
(
char
(
1
)
,@wt_count)
exec
dbccdb..sp_dbcc_updateconfig dbccdb, "max worker processes"
, "5"
select
@str1=
convert
(
varchar
(
6
)
,@cache_size)+
"K"
exec
dbccdb..sp_dbcc_updateconfig @dbname, "dbcc named cache"
, @cache
, @str1
exec
dbccdb..sp_dbcc_updateconfig @dbname, "scan workspace"
, @sws
exec
dbccdb..sp_dbcc_updateconfig @dbname, "text workspace"
, @tws
fetch
cursor_dbcc_config into
@dbname, @scanws_size, @textws_size, @wt_count, @cache_size
print
""
end
close
cursor_dbcc_config
/*
** Nettoyage des tables temporaires
*/
deallocate
cursor
cursor_dbcc_dblist
deallocate
cursor
cursor_dbcc_config
drop
table
#dbcc_config
drop
table
#dbcc_dblist
drop
table
#caches
return
(
0
)
end
go
grant
execute
on
sp_dbcc_init to
sa_role
go
3. Configuration de checkstorage▲
Reste à récolter ce que nous venons de semer. Configurons donc notre outil en lançant simplement
execute
dbccdb..sp_dbcc_init
Puis validons nos paramètres en les contrôlant via la SP officielle de Sybase
execute
dbccdb..sp_dbcc_evaluatedb
4. Utilisation de checkstorage▲
Il ne nous reste plus qu'à exécuter le dbcc checkstorage. Couplé au dbcc checkcatalog, il couvre le spectre de la totalité des outils de contrôle.
dbcc checkcatalog (
MaBase)
if
@@error
=
0
print
"Catalogue en ordre"
else
print
"Erreur lors du checkcatalog"
dbcc checkstorage (
MaBase)
if
@@error
=
0
print
"Checkstorage en ordre"
else
print
"Erreur lors du checkstorage"