Bonjour a tous,

Il est rare que je fasse appel a la communauté pour me sortir d'un soucis, en général je trouve ce qu'il me faut sur le net mais la j'ai fais choux blanc.

Sur mes plateformes principales (SQL2012 SP3, edition Entreprise, Groupe de disponibilité AlwaysOn) je rencontre de manière aléatoire un problème étrange. Afin d'appliqué un traitement particulier a l'ensemble des bases d'un de mes groupe de disponibilité j'utilise des jobs appelant un curseur listant les bases a traité et générant dynamiquement le code a executer pour chaque base. En voici un exemple :

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
 
DECLARE @errnum int
DECLARE @errmess nvarchar(4000)
DECLARE @ret int
DECLARE @NbBaseTheo int
DECLARE @NbBaseTrt int
DECLARE @NbBaseErr int
DECLARE @IamThePrimary Int
DECLARE @sqlorder nvarchar(max)
DECLARE @DBNAME sysname
DECLARE CUR_DB CURSOR
FOR select name from sys.databases
where name not in ('master', 'msdb', 'tempdb', 'model', 'ANNUAIRE_ZEPHYR')
and name not like '%OFFLINE%' and name not like 'META%' and name not like 'LOADGEN%'
order by name
 
BEGIN
 
SET @IamThePrimary = 0
SELECT @IamThePrimary = 1
FROM [master].[sys].[dm_hadr_availability_replica_states] as DMHA
inner join [master].[sys].[availability_replicas] as SYAR
	ON DMHA.replica_id = SYAR.replica_id
WHERE DMHA.[role] = 1
AND SYAR.[replica_server_name] = @@SERVERNAME
 
IF (@IamThePrimary = 1)
BEGIN
select @NbBaseTheo=count(name) from sys.databases where name not in ('master', 'msdb', 'tempdb', 'model', 'ANNUAIRE_ZEPHYR')
and name not like '%OFFLINE%' and name not like 'META%' and name not like 'LOADGEN%'
set @NbBaseTrt = 0
set @NbBaseErr = 0
PRINT 'Debut traitement ' + cast(@NbBaseTheo as varchar) +' bases a traiter'
OPEN CUR_DB
FETCH NEXT FROM CUR_DB
INTO @DBNAME
WHILE @@FETCH_STATUS = 0 
Begin Try
BEGIN
SET @sqlorder= 'IF EXISTS (SELECT * FROM '+@DBNAME+'.sys.objects WHERE object_id = OBJECT_ID(N''['+@DBNAME+'].[data].[PS_Refresh_Ofr_Cde_EnCours]'') AND type in (N''P'', N''PC''))
BEGIN
exec ['+@DBNAME+'].[data].[PS_Refresh_Ofr_Cde_EnCours]
END'
SET @ret = 0
exec @ret = sp_executesql @sqlorder
IF @ret =0 
BEGIN
PRINT @sqlorder+'  ==> OK'
set @NbBaseTrt = @NbBaseTrt +1
FETCH NEXT FROM CUR_DB INTO @DBNAME
END
IF @ret <> 0 
BEGIN
PRINT @sqlorder+'  ==> KO'
SET @errnum = ERROR_NUMBER();
SET @errmess = ERROR_MESSAGE()
PRINT @errmess
RAISERROR(60001,17,1, @errnum, @errmess) ;
END
END
END TRY
BEGIN CATCH
PRINT @sqlorder  + ' KO'
set @NbBaseErr = @NbBaseErr +1
SET @errnum = ERROR_NUMBER();
SET @errmess = ERROR_MESSAGE() + N' Base : '+ @DBNAME ;
RAISERROR(60001,17,1, @errnum, @errmess) ;
FETCH NEXT FROM CUR_DB INTO @DBNAME
END CATCH
CLOSE CUR_DB 
DEALLOCATE CUR_DB
PRINT 'Etat du Fetch_Status = ' + cast(@@FETCH_STATUS as nvarchar)
PRINT 'Fin traitement ' + cast(@NbBaseTrt as varchar) +' bases traitées, ' + cast(@NbBaseErr as varchar) + ' bases en erreur'
SET @errmess = 'Le nombre de base a traiter etait de ' + cast(@NbBaseTheo as varchar) +' mais seul '+ cast(@NbBaseTrt+@NbBaseErr as varchar)+' l''ont été'
IF @NbBaseTrt+@NbBaseErr <> @NbBaseTheo RAISERROR(60001,17,1, 60001, @errmess) ;
END
END
Je me suis rendu compte que lors de certains lancement de ces jobs, certaines bases n'étaient pas traitées toutefois le job ne semblait rencontrer aucune erreur, ne passait jamais dans le catch et ne signalait aucun problème, j'ai donc ajouter la petite astuce finale de comptage des bases a traiter en théorie et du nombre réellement traitées et je déclenche un erreur si ils ne sont pas égaux. Cela m'aide a superviser mais pas a comprendre pourquoi toutes les bases ne sont pas traiter (de manière aléatoire, la plus part des lancements des jobs traitent correctement toutes les bases).
J'ai donc aussi ajouter en dernier lieu l'etat du fetch status afin de comprendre pourquoi ma boucle s'arrêtait :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
 
Etat du Fetch_Status = -2 [SQLSTATE 01000]
Fin traitement 80 bases traitées, 0 bases en erreur [SQLSTATE 01000]
Msg 60001, Sev 17, State 1, Line 75 : Une erreur 60001 est survenue avec le texte Le nombre de base a traiter était de 91 mais seul 80 l'ont été [SQLSTATE 42000]
J'ai donc un FETCH_STATUS à -2, d'après MSDN :
-2 The row fetched is missing.

Et la j'avoue que je ne sais pas du tout ce qui provoque ça. Aussi, quelqu'un peut il m'éclairer ?