I. Introduction

Issue de l'époque lointaine (au moins 10 ans !) ou il n'était pas aisé de faire cohabiter une grosse masse d''information sur de nombreux raw devices, ventilés sur de non moins nombreux disques, la gestion des fichiers de donnée sous Sybase ASE peut paraître quelque peu complexe au néophyte.

Le prix à payer à ce jour est une mauvaise compréhension de la complexité de la gestion des espaces de stockage du DBA Junior, et la mécompréhension de l'inexistence de 2 spécificités existant déjà dans d'autres SGBDR :

  1. L'inexistence d'une clause AUTOEXTENT lors de la création de devices
  2. L'incapacité de réduire la taille d'un device ayant été trop largement taillé (cf. autre article du même auteur)

Cet article à pour but d'apporter une solution à la soit disant impossibilité qu'à ASE d'auto-étendre ses devices.

II. L'explication historique

Sybase ASE (anciennement Sybase SQL Server) permettait en fait de définir avant tout ses espaces de stockage, puis ensuite de tailler dans lesdits espaces les segments nécessaires à chaque base de données.

Il faut garder en mémoire que jusqu'en version 11.9, le seul système de stockage supporté en production était le raw device. Il permettait d'assurer une intégrité des accès disques à ASE (en évitant tout cache OS). Ce raw device était généralement créé par l'administrateur système, et non pas par l'administrateur de la base. Une fois cet espace créé, sa taille ne pouvait varier... ce qui explique que l'autoextension ou la réduction du fichier ne pouvait être une option au niveau de l'instance ASE.

Nous avions donc une application claire de ce que Codd souhaitait : une dissociation claire et nette de la partie logique (base de données, tables) et de la partie physique (devices, fichiers sur disques, ...).

Ce qui différencie donc ASE de la plupart de ses concurrents, et ce qui explique certaines contraintes, c'est que l'on y crée des devices neutres. Ce n'est qu'à l'affection de zones que l'on détermine leur contenu, et que le contenu peut être variable. C'est d'ailleurs pour cela que le stockage des informations sur les devices se fait dans la table sysdevices de master, puis que c'est ensuite une table de liens master..sysusages qui stocke le partages des devices de sysdevices avec les dbid de sysdatabases.

Découpage des devices et des segments de base
sysusages

Microsoft a cassé cette logique dès la version 2000 en rapatriant les informations de stockage dans la base elle-même, et en dissociant fortement les fichiers de données (.mdb) et ceux du journal de transactions (.ldb).

Si l'on se base sur un modèle contraignant, évitant ainsi les écueils, on peut automatiser les choses.

III. Simulation d'autoextension : un exemple

En fait, il suffit de jouer avec la procédure stocké sp_thresholdaction qui n'est rien d'autre qu'un configurateur de seuils d'alerte pour les segments.

Basons-nous sur le modèle contraignant suivant:

  1. Une base est propriétaire de ses propres fichiers (pas de fichiers partagés entres bases)
  2. Le journal de transaction est toujours dissocié
  3. On crée arbitrairement 3 types de segments qui auront eux aussi leur(s) propre(s) fichier(s)
  4. Chaque segment utilise l'entièreté de son device associé

Il faut avant tout créer une procédure stockée de seuil qui augmentera la taille des devices et des segments au moment critique. Son positionnement dans master est nécessaire à cause de la commande disk remap.

 
Sélectionnez
use master 
go 
 
create procedure dbo.sp_auto_db_etend 
( @dbname varchar(30), @segment_name varchar(30), @space_left int, @status int) 
as 
begin 
 
declare @v_size varchar(5) 
declare @v_device varchar(30) 
declare @v_type varchar(5) 
declare @v_sql varchar(200) 
 
if @segment_name = 'default' 
    select @v_device=@dbname+'_D01', @v_size='100M', @v_type='' 
else 
if @segment_name = 'system' 
    select @v_device=@dbname+'_D01', @v_size='100M', @v_type='' 
else 
if @segment_name = 'indexsegment' 
    select @v_device=@dbname+'_I01', @v_size='100M', @v_type='' 
else 
if @segment_name = 'logsegment' 
    select @v_device=@dbname+'_L01', @v_size='50M', @v_type='LOG' 
else 
    begin 
    raiserror 20001 'Type de segment non géré' 
    return -1 
    end   
 
disk resize name = @v_device, size = @v_size 
 
select @v_sql = 'alter database '+@dbname+' '+@v_type+' ON '+@v_device+'='''+@v_size+'''' 
print @v_sql 
exec (@v_sql) 
return 0 
end 
go 

La procédure stocké suivante automatise la création d'une base de données selon les critères spécifiques et détermine le seuil critique.

 
Sélectionnez
user master 
go 
create procedure sp_auto_db_cree 
( @v_dbname varchar ( 30 )) 
as 
begin 
 
    declare @v_sql varchar ( 200 ) 
    declare @v_path varchar ( 200 ) 
    declare @v_file varchar ( 200 ) 
    declare @v_seg varchar ( 30 ) 
    declare @v_num_dev int 
    declare @v_max_dev int 
 
    /* Contrôle de la préexistance de la base */ 
 
    if exists (select name from sysdatabases where name = @v_dbname) 
        begin 
        raiserror 20001 "La base  existe déjà" 
        return -1 
        end 
 
 
    /* Contrôle du nombre de devices configuré */ 
 
    select @v_max_dev=value from sysconfigures where name = 'number of devices' 
    select @v_num_dev=count(*) from sysdevices 
 
    if @v_max_dev < @v_num_dev + 3 -- manque de structures mémoire pour les devices 
        begin 
        select @v_num_dev=@v_max_dev + 3 
        exec sp_configure 'number of devices', @v_num_dev 
        end 
 
    /* Creation des devices specifiques */ 
 
    select @v_path = left ( phyname , datalength ( phyname )- 10 ) from master..sysdevices where name = 'master' 
 
    select @v_seg=@v_dbname+'_D01', @v_file=@v_path + @v_dbname + '_DATA01.dat' 
    disk init  name= @v_seg, physname=@v_file , size='100M' 
 
    select @v_seg=@v_dbname+'_I01', @v_file=@v_path + @v_dbname + '_INDEX01.dat' 
    disk init  name= @v_seg, physname=@v_file , size='100M' 
 
    select @v_seg=@v_dbname+'_L01', @v_file=@v_path + @v_dbname + '_LOG01.dat' 
    disk init  name= @v_seg, physname=@v_file , size='50M' 
 
    /* Creation de la base */ 
    select @v_sql = 'create database ' + @v_dbname + ' on ' + @v_dbname + '_D01=''100M'' log on ' + @v_dbname + '_L01=''50M''' 
    exec ( @v_sql ) 
 
    select @v_sql = 'alter database ' + @v_dbname + ' on ' + @v_dbname + '_I01=''100M''' 
    exec ( @v_sql ) 
 
    /* Attribution des segments */ 
    select @v_sql = @v_dbname+'..sp_addsegment ''indexsegment'', '+@v_dbname+', '+@v_dbname+'_I01' 
    exec (@v_sql) 
 
    select @v_sql = @v_dbname+'..sp_dropsegment ''default'', '+@v_dbname+', '+@v_dbname+'_I01' 
    exec (@v_sql) 
 
    select @v_sql = @v_dbname+'..sp_dropsegment ''system'', '+@v_dbname+', '+@v_dbname+'_I01' 
    exec (@v_sql) 
 
   /* Délimitation des seuil d'alerte */ 
 
   select @v_sql = @v_dbname+'..sp_addthreshold '+@v_dbname+', system, 5120, sp_auto_db_etend' 
    exec (@v_sql) 
 
   select @v_sql = @v_dbname+'..sp_addthreshold '+@v_dbname+', default, 5120, sp_auto_db_etend' 
    exec (@v_sql) 
 
   select @v_sql = @v_dbname+'..sp_addthreshold '+@v_dbname+', indexsegment, 5120, sp_auto_db_etend' 
    exec (@v_sql) 
 
   select @v_sql = @v_dbname+'..sp_addthreshold '+@v_dbname+', logsegment, 5120, sp_auto_db_etend' 
    exec (@v_sql) 
return 0 
end 
go 
 

Certains choix ont été fait afin de simplifier la démonstration :

  • Localisation des devices dans un répertoire unique, à savoir celui hébergeant le device master : en terme de performances, il serait judicieux de choisir des disques distincts pour les divers segments
  • Création arbitraire d'un device de 100M (50M pour les logs)
  • Augmentation arbitraire d'un device de 100M (50M pour les logs)
  • Trois segments distincts (data/system, log et index)

Il sera cependant aisément possible d'améliorer la procédure en "piochant" les informations modifiables via une table de configuration.

Cette solution n'est pas optimum : elle a cependant le mérite de donner les pistes nécessaires à la résolution de cette problématique.

IV. Références