IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Développement SQL Server Discussion :

Optimisation trigger journalisation


Sujet :

Développement SQL Server

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    72
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 72
    Points : 84
    Points
    84
    Par défaut Optimisation trigger journalisation
    Salut à tous, j'ai essayé de créer un trigger de journalisation... je m'explique, lors d'un update, je veux enregistrer dans une table

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    create table tcd_history(
    	ID integer primary key identity,
    	who varchar(64),
    	action varchar(20),
    	field varchar(200) default null,
    	date datetime,
    	old_value varchar(500) default null,
    	entity varchar(200),
    	pk_name varchar(500),
    	pk_value varchar(650)
    );
    les modifs qui lui sont faites.

    J'ai beaucoup de table, et je ne veux pas faire un trigger spécifique à chaque table, je veux quelque chose de modulaire...

    Pour le moment, j'ai ça :


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
     
    CREATE trigger trigger_test on dbo.une_table
    for update
    as
    begin
     
    	declare @user varchar(150);
    	declare @entity varchar(200);
    	declare @action varchar(30);
    	declare @columnName varchar(100);
    	declare @columnType varchar(100);
    	declare @strListPKeys varchar(700);
    	declare @strListPKeysVal varchar(700);
    	declare @countUpdated integer;
     
    	set @countUpdated=(select count(*) from Inserted);
     
    	if @countUpdated=1
    	begin
     
    		select * into inserted_table from Inserted;
    		select * into deleted_table from Deleted;
     
    		set @entity=(select object_name(parent_obj) from sysobjects where id=@@PROCID);
     
    		declare myCursor cursor local for
    		SELECT C.COLUMN_NAME, C.DATA_TYPE
    		FROM   INFORMATION_SCHEMA.COLUMNS C
    		       INNER JOIN INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
    		             ON     C.TABLE_CATALOG = TC.TABLE_CATALOG
    		                AND C.TABLE_SCHEMA  = TC.TABLE_SCHEMA
    		                AND C.TABLE_NAME    = TC.TABLE_NAME
    		       INNER JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CCU
    		             ON     TC.CONSTRAINT_CATALOG = CCU.CONSTRAINT_CATALOG
    		                AND TC.CONSTRAINT_SCHEMA  = CCU.CONSTRAINT_SCHEMA
    		                AND TC.CONSTRAINT_NAME    = CCU.CONSTRAINT_NAME
    		                AND C.COLUMN_NAME         = CCU.COLUMN_NAME
    		WHERE  TC.TABLE_SCHEMA    = 'dbo'
    		  AND  TC.TABLE_NAME      = @entity
    		  AND  TC.CONSTRAINT_TYPE = 'PRIMARY KEY';
     
    		open myCursor;
    		fetch next from myCursor into @columnName,@columnType;
    		if @@fetch_status = 0
    		begin
    			set @strListPKeys=@columnName+'['+@columnType+']';
    			declare @req varchar(300);
    			set @req='select '+@columnName+' from inserted_table';
     
     
    			declare @cursor int;
    			exec sp_cursoropen @cursor OUTPUT,@req,2,8193;
    			exec sp_cursoroption @cursor,2,'myTempCursor';
    			declare @x cursor;
    			exec sp_describe_cursor @x out,N'global','myTempCursor';
    			fetch next from @x;
    			declare @val sql_variant;
    			fetch next from myTempCursor into @val;
    			set @strListPKeysVal=rtrim(convert(char(150),@val));
    			close myTempCursor;
    			deallocate myTempCursor;
    			close @x;
    			deallocate @x;
    		end
    		fetch next from myCursor into @columnName,@columnType;
    		while @@fetch_status = 0
    		begin
    			--char 254
    			set @strListPKeys=@strListPKeys+'£'+@columnName+'['+@columnType+']';
    			set @req='select '+@columnName+' from inserted_table';
     
    			exec sp_cursoropen @cursor OUTPUT,@req,2,8193;
    			exec sp_cursoroption @cursor,2,'myTempCursor';
    			exec sp_describe_cursor @x out,N'global','myTempCursor';
    			fetch next from @x;
    			fetch next from myTempCursor into @val;
     
    			set @strListPKeysVal=@strListPKeysVal+'£'+rtrim(convert(char(150),@val));
    			close myTempCursor;
    			deallocate myTempCursor;
    			close @x;
    			deallocate @x;
     
    			fetch next from myCursor into @columnName, @columnType;
    		end
    		close myCursor;
    		deallocate myCursor;
     
    		set @user=(select current_user);
    		set @action='update';
     
     
     
    		declare cursorCols cursor local for SELECT COLUMN_NAME
    		FROM INFORMATION_SCHEMA.COLUMNS
    		WHERE TABLE_NAME=@entity;
     
    		open cursorCols;
     
    		declare @modified integer;
     
    		fetch next from cursorCols into @columnName;
    		while @@fetch_status=0
    		begin
    			exec('select count(*) as modif into get_modif_table from inserted_table i, deleted_table d where i.'+@columnName+'<>d.'+@columnName);
    			set @modified=(select modif from get_modif_table);
    			if @modified=1
    			begin
     
    				set @req='select '+@columnName+' from deleted_table';
     
    				exec sp_cursoropen @cursor OUTPUT,@req,2,8193;
    				exec sp_cursoroption @cursor,2,'myTempCursor';
    				exec sp_describe_cursor @x out,N'global','myTempCursor';
    				fetch next from @x;
    				fetch next from myTempCursor into @val;
    				close myTempCursor;
    				deallocate myTempCursor;
    				close @x;
    				deallocate @x;
     
    				insert into tcd_history(who,action,field,date,old_value,entity,pk_name,pk_value) values(@user,@action,@columnName,getdate(),rtrim(convert(varchar,@val)),@entity,@strListPKeys,@strListPKeysVal);
    			end
    			drop table get_modif_table;
     
    			fetch next from cursorCols into @columnName;
    		end
    		close cursorCols;
     
     
    		drop table inserted_table;
    		drop table deleted_table;
    	end
    end

    Mon problème est que d'une part je ne voudrais pas que la procedure retourne les lignes pointées dans les curseurs internes au trigger (est-ce possible ?) et d'autre part c'est un peu lent (meilleures idées ??).

    Pourriez-vous m'aider à optimiser mon trigger
    Grand merci

  2. #2
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 774
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 774
    Points : 52 744
    Points
    52 744
    Billets dans le blog
    5
    Par défaut
    Votre trigger va être particulièrement catastrophique en terme de performances. De plus votre table de suivi des modif n'est pas correcte. Commençons par cette dernière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    CREATE TABLE T_S_HISTORIQUE_HST
    (HST_ID            INT PRIMARY KEY identity,
     HST_USER          VARCHAR(64),
     HST_ACTION        CHAR(1) CHECK (HST_ACTION IN ('I', 'U', 'D')),
     HST_SCHEMA_NAME   sysname NOT NULL,
     HST_TABLE_NAME    sysname NOT NULL,
     HST_COLUMN_NAME   sysname NOT NULL,
     HST_VAL_CLEF      VARCHAR(256),
     HST_HORODATAGE    DATETIME DEFAULT CURRENT_TIMESTAMP,
     HST_VAL_AVANT     SQL_VARIANT,
     HST_VAL_APRES     SQL_VARIANT);
    Ensuite il faut créer vos trigger de manière dynamique et s'interdire tout code de type curseur.
    Enfin, veillez à placer en tête du code le mot clef COMMIT TRANSACTION de façon a ce que la transaction courante ne soit pas allongée par le teps de traitement du trigger.
    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    72
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 72
    Points : 84
    Points
    84
    Par défaut
    Tout d'abord merci, pour ces éléments de réponse.

    Ensuite il faut créer vos trigger de manière dynamique et s'interdire tout code de type curseur
    Je n'ai pas compris le sens de créer les triggers de manière dynamique (c'est quoi). D'autre part je ne sais pas comment éviter d'utiliser des curseurs.

    C'est possible avec mes contraintes ?

    Merci

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    72
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 72
    Points : 84
    Points
    84
    Par défaut
    ah pardon je crois savoir... je fais une procédure stockée par exemple qui à partir du nom d'une table me créer une requête de création du trigger spécifique à cette table... Du coup plus besoin d'analyser le schéma de la table à chaque passage dans le trigger.

    J'ai bien compris ?

  5. #5
    Rédacteur

    Avatar de SQLpro
    Homme Profil pro
    Expert bases de données / SQL / MS SQL Server / Postgresql
    Inscrit en
    Mai 2002
    Messages
    21 774
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Expert bases de données / SQL / MS SQL Server / Postgresql
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 21 774
    Points : 52 744
    Points
    52 744
    Billets dans le blog
    5
    Par défaut
    Vous êtes sur la bonne voie. Ce n'est pas simple, mais faisable....

    Cepandant je ne conseille JAMAIS de faire ce genre de chose. Il y a d'autres moyens, comme de passer par des procédures stockées et s'interdire toute anipulation des données par des requêtes ad hoc.

    A +
    Frédéric Brouard - SQLpro - ARCHITECTE DE DONNÉES - expert SGBDR et langage SQL
    Le site sur les SGBD relationnels et le langage SQL: http://sqlpro.developpez.com/
    Blog SQL, SQL Server, SGBDR : http://blog.developpez.com/sqlpro
    Expert Microsoft SQL Server - M.V.P. (Most valuable Professional) MS Corp.
    Entreprise SQL SPOT : modélisation, conseils, audit, optimisation, formation...
    * * * * * Expertise SQL Server : http://mssqlserver.fr/ * * * * *

  6. #6
    Membre régulier
    Profil pro
    Inscrit en
    Décembre 2005
    Messages
    72
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Décembre 2005
    Messages : 72
    Points : 84
    Points
    84
    Par défaut


    Je vais me contenter de cela :

    à un moment donné je génère le curseur dynamiquement sur la structure de la table passée en paramètre d'une procédure stockée...

    J'ai simplifié, je n'ai pas besoin de gérer les schémas...

    Je donne ma solution pour aider les autres...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
     
     
    create procedure createTriggersJournalizing(@table sysname)
    as
    begin
    	declare @updateQuery varchar(8000);
    	declare @insertQuery varchar(8000);
    	declare @deleteQuery varchar(8000);
    	declare @decl varchar(600);
     
    	declare @columnName varchar(60);
    	declare @counter int;
    	declare @tableName varchar(60);
    	declare @triggerUName varchar(200);
    	declare @triggerIName varchar(200);
    	declare @triggerDName varchar(200);
    	declare @strPKey varchar(600);
     
    	set @tableName=@table;
    	set @triggerUName='trigger_u_'+@tableName;
    	set @triggerIName='trigger_i_'+@tableName;
    	set @triggerDName='trigger_d_'+@tableName;
     
    	if object_id(@triggerUName) is not null
    	begin
    		exec('drop trigger '+@triggerUName+';');
    	end
     
    	if object_id(@triggerIName) is not null
    	begin
    		exec('drop trigger '+@triggerIName+';');
    	end
     
    	if object_id(@triggerDName) is not null
    	begin
    		exec('drop trigger '+@triggerDName+';');
    	end
     
    	set @decl='declare @user  varchar(64);'+char(13)+char(10);
    	set @decl=@decl+'declare @action char(1);'+char(13)+char(10);
    	set @decl=@decl+'declare @tableName sysname;'+char(13)+char(10);
    	set @decl=@decl+'declare @keyValue varchar(256);'+char(13)+char(10);
    	set @decl=@decl+'set @keyValue='''';'+char(13)+char(10);
    	set @decl=@decl+'set @user=(select current_user);'+char(13)+char(10);
    	set @decl=@decl+'set @tableName=(select object_name(parent_obj) from sysobjects where id=@@PROCID);'+char(13)+char(10);
     
    	set @deleteQuery='create trigger '+@triggerDName+' on dbo.'+@tableName+char(13)+char(10);
    	set @deleteQuery=@deleteQuery+'for delete'+char(13)+char(10)+'as'+char(13)+char(10)+'begin'+char(13)+char(10);
    	set @deleteQuery=@deleteQuery+@decl;
    	set @deleteQuery=@deleteQuery+'set @action=''D'';'+char(13)+char(10);
     
     
    	set @insertQuery='create trigger '+@triggerIName+' on dbo.'+@tableName+char(13)+char(10);
    	set @insertQuery=@insertQuery+'for insert'+char(13)+char(10)+'as'+char(13)+char(10)+'begin'+char(13)+char(10);
    	set @insertQuery=@insertQuery+@decl;
    	set @insertQuery=@insertQuery+'set @action=''I'';'+char(13)+char(10);
     
    	set @counter=0;
     
    	set @updateQuery='create trigger '+@triggerUName+' on dbo.'+@tableName+char(13)+char(10);
    	set @updateQuery=@updateQuery+'for update'+char(13)+char(10)+'as'+char(13)+char(10)+'begin'+char(13)+char(10);
    	set @updateQuery=@updateQuery+@decl;
    	set @updateQuery=@updateQuery+'declare @oldValue sql_variant;'+char(13)+char(10);
    	set @updateQuery=@updateQuery+'declare @newValue sql_variant;'+char(13)+char(10);
    	set @updateQuery=@updateQuery+'set @action=''U'';'+char(13)+char(10);
     
     
    	declare myCursor cursor local for select C.COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS C
    	       inner join INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
    	             on     C.TABLE_CATALOG = TC.TABLE_CATALOG
    	                and C.TABLE_SCHEMA  = TC.TABLE_SCHEMA
    	                and C.TABLE_NAME    = TC.TABLE_NAME
    	       inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CCU
    	             on     TC.CONSTRAINT_CATALOG = CCU.CONSTRAINT_CATALOG
    	                and TC.CONSTRAINT_SCHEMA  = CCU.CONSTRAINT_SCHEMA
    	                and TC.CONSTRAINT_NAME    = CCU.CONSTRAINT_NAME
    	                and C.COLUMN_NAME         = CCU.COLUMN_NAME
    	where  TC.TABLE_SCHEMA    = 'dbo'
    	  and  TC.TABLE_NAME      = @tableName
    	  and  TC.CONSTRAINT_TYPE = 'PRIMARY KEY'
    	order by ORDINAL_POSITION;
     
    	open myCursor;
    	fetch next from myCursor into @columnName;
     
    	while @@fetch_status = 0
    	begin
    		set @counter=@counter+1;
    		set @strPKey='declare @key'+convert(varchar(4),@counter)+' sql_variant;'+char(13)+char(10);
    		set @strPKey=@strPKey+'set @key'+convert(varchar(4),@counter)+'=(select '+@columnName+' from Inserted);'+char(13)+char(10);
    		if @counter=1
    		begin
    			set @strPKey=@strPKey+'set @keyValue=rtrim(convert(varchar(200),@key'+convert(varchar(4),@counter)+'));'+char(13)+char(10);
    		end
    		else
    		begin
    			set @strPKey=@strPKey+'set @keyValue=@keyValue+''£''+rtrim(convert(varchar(200),@key'+convert(varchar(4),@counter)+'));';
    		end
    		set @updateQuery=@updateQuery+@strPKey;
    		set @insertQuery=@insertQuery+@strPKey;
    		set @deleteQuery=@deleteQuery+@strPKey;
    		fetch next from myCursor into @columnName;
    	end
     
    	close myCursor;
    	deallocate myCursor;
     
    	set @deleteQuery=@deleteQuery+'insert into tcd_history(who,action,table_name,key_value) values(@user,@action,@tableName,@keyValue);'+char(13)+char(10);
    	set @insertQuery=@insertQuery+'insert into tcd_history(who,action,table_name,key_value) values(@user,@action,@tableName,@keyValue);'+char(13)+char(10);
     
    	--set @updateQuery=@updateQuery+'commit transaction;'+char(13)+char(10);
     
    	declare cursorFields cursor local for select COLUMN_NAME
    	from INFORMATION_SCHEMA.COLUMNS
    	where TABLE_NAME=@tableName
    	and COLUMN_NAME not in (select C.COLUMN_NAME from INFORMATION_SCHEMA.COLUMNS C
    		       inner join INFORMATION_SCHEMA.TABLE_CONSTRAINTS TC
    		             on     C.TABLE_CATALOG = TC.TABLE_CATALOG
    		                and C.TABLE_SCHEMA  = TC.TABLE_SCHEMA
    		                and C.TABLE_NAME    = TC.TABLE_NAME
    		       inner join INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE CCU
    		             on     TC.CONSTRAINT_CATALOG = CCU.CONSTRAINT_CATALOG
    		                and TC.CONSTRAINT_SCHEMA  = CCU.CONSTRAINT_SCHEMA
    		                and TC.CONSTRAINT_NAME    = CCU.CONSTRAINT_NAME
    		                and C.COLUMN_NAME         = CCU.COLUMN_NAME
    		where  TC.TABLE_SCHEMA    = 'dbo'
    		  and  TC.TABLE_NAME      = @tableName
    		  and  TC.CONSTRAINT_TYPE = 'PRIMARY KEY');
     
    	open cursorFields;
     
    	fetch next from cursorFields into @columnName;
     
    	while @@fetch_status=0
    	begin
    		set @updateQuery=@updateQuery+'if update('+@columnName+')'+char(13)+char(10);
    		set @updateQuery=@updateQuery+'begin'+char(13)+char(10);
    		set @updateQuery=@updateQuery+'set @oldValue=(select '+@columnName+' from Deleted);'+char(13)+char(10);
    		set @updateQuery=@updateQuery+'set @newValue=(select '+@columnName+' from Inserted);'+char(13)+char(10);
    		set @updateQuery=@updateQuery+'insert into tcd_history(who,action,table_name,key_value,column_name,column_old_value,column_new_value) values(@user,@action,@tableName,@keyValue,'''+@columnName+''',@oldValue,@newValue);'+char(13)+char(10);
     
    		set @updateQuery=@updateQuery+'end'+char(13)+char(10);
     
    		fetch next from cursorFields into @columnName;
    	end
     
    	close cursorFields;
    	deallocate cursorFields;
     
    	set @updateQuery=@updateQuery+char(13)+char(10)+'end';
    	set @insertQuery=@insertQuery+char(13)+char(10)+'end';
    	set @deleteQuery=@deleteQuery+char(13)+char(10)+'end';
     
    	exec(@updateQuery);
    	exec(@insertQuery);
    	exec(@deleteQuery);
     
    end
    Et merci pour l'aide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Optimisation d'une requête pour l'utiliser dans trigger
    Par Skandyx dans le forum Développement
    Réponses: 1
    Dernier message: 29/11/2012, 09h12
  2. Comment optimiser le temps de traitement d'un trigger ?
    Par frp31 dans le forum SQL Procédural
    Réponses: 0
    Dernier message: 26/03/2010, 09h49
  3. Optimisation trigger Oracle
    Par sebv33 dans le forum SQL
    Réponses: 2
    Dernier message: 20/11/2008, 14h32
  4. Optimisation Trigger sous SQL Serveur 2000
    Par Silvia12 dans le forum Développement
    Réponses: 3
    Dernier message: 30/05/2007, 18h26
  5. Trigger de journalisation
    Par alah_1 dans le forum Développement
    Réponses: 6
    Dernier message: 20/11/2006, 15h24

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo