Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

aide sur store proc

4 réponses
Avatar
Jean BONBEUR
bonjour, dans le cadre d'un projet web pour un client, nous utilisons des
store proc, et j'aimerais avoir votre avi par rapport aux performances entre
deux façons de l'implanter.
la proc à pour objectif de faire un SELECT, et le client choisi dans une
fenetre des criteres de filtrage. il ne saisit pas de SQL, c'est juste deux
ou trois textbox dans lequelles on saisi des valeurs. si il y'a une valeur,
le critere s'applique, sinon, il ne s'applique pas. on transfert dans la
storeproc par des param, et si un param est null, le critere s'applique,
sinon, il ne s'applique pas.

un exemple simple avec @montanMin et @montantMax :

SELECT id , montant WHERE ( @montanMin=NULL OR @montanMin<=montant ) AND (
@montantMax=NULL OR montant<=@montantMax ) ORDER BY montant ASC

une deuxime technique consiste à construire le SQL dans une chaine de
caractere, et à l'executer avec la commande EXEC

un appel à la proc avec @montanMin = NULL et @montantMax = 500 donnerait :

@sql = ...
-- @sql contient SELECT id , montant WHERE AND montant<=500 ORDER BY montant
ASC
EXEC (@sql)

maintenant, sachant que des indexs sont posés sur montant, quelle est la
solution qui va produire les meilleurs temps de réponse ? EXEC fabrique t'il
un plan d'execution from scratch qui soit assez efficace ? l'optimiseur sait
il optimiser la proc 1 en quelque chose du style :

if(@montanMin IS NULL)
if(@montantMax IS NULL)
SELECT id , montant ORDER BY montant ASC
else
SELECT id , montant WHERE montant<=@montantMax ORDER BY montant ASC
else
if(@montantMax IS NULL)
SELECT id , montant WHERE @montanMin<=montant ORDER BY montant ASC
else
SELECT id , montant WHERE @montanMin<=montant AND montant<=@montantMax
ORDER BY montant ASC


comment puis-je évaluer la complexité d'une requete qui va etre appellée
dans EXEC(@sql) au sein d'une store proc ? est-ce que c'est pareil en perfs
de faire EXEC @sql, et de construire du SQL côté appli, et l'executer au
moyen d'une DbCommand. si c'est le cas, tant mieux, le sql dans du sql,
c'est illisible, pas debbugable, etc etc...

maintenant, voici le cas réel qui me préoccupe, suivi d'un exemple de ce que
contient @strRequete qui va passer dans l'exec : ça constuit 4 SELECT
qu'on UNION, et dont on ORDER BY le résultat.
outre la différence entre les deux methodes, voyez vous des choses qui sont
des enormités, des oublis, des problemes éventuels ?

merci d'avance pour votre aide, j'en ai sacrément besoin...


Frédéric





CREATE Proc dbo.dsm_Memo_ChargerMemo
(
@nbMaxEnregistrements int,
@gestionnaireConnecteID int,
@gestionnaireConnectePROFIL varchar(4),
@gestionnaireSelectionne int,
@dateFin datetime = null,
@operationDateFin varchar(2) = null,
@montantCreance money = null,
@operationMontant varchar(2) = null,
@pictogramme int = null,
@numeroFacture varchar(50) = null
)
AS
BEGIN
/******************/
/* Initialisation */
/******************/
set nocount on
set rowcount @nbMaxEnregistrements

/** Déclaration des variables indispensables au traitement **/
declare @procid int, /* Identifiant de la proc */
@status int, /* Gestion d'erreur */
@strRequete varchar(8000),
@strRequete1 varchar(8000),
@strRequete2 varchar(8000),
@strRequete3 varchar(8000),
@strRequete4 varchar(8000),
@strWhere1 varchar(8000),
@strWhere2 varchar(8000),
@strWhere3 varchar(8000),
@strWhere4 varchar(8000),
@sAnd1 char(4),
@sAnd2 char(4),
@sAnd3 char(4),
@sAnd4 char(4),
@sTmp varchar(1000)

/** Initialisation des variables utilisees dans les controles d'erreurs **/
select @procid = @@procid,
@status = 0,
@sAnd1 = '',
@sAnd3 = '',
@sAnd2 = '',
@sAnd4 = ' AND ',
@strWhere1=null,
@strWhere2=null,
@strWhere3=null,
@strWhere4=' '

/***************************************************/
/* Vérification de la validité des paramètres */
/***************************************************/

/** Contrôle de la présence du paramètre @nbMaxEnregistrements **/
exec @status=Ctl_Presence 'Nombre maximal d enregistrements a retourner',
@nbMaxEnregistrements, @procid, 'N' , 'O'
if ( @status = 1 ) goto FinProc

/** Contrôle de la présence du paramètre @gestionnaireConnecteID **/
exec @status=Ctl_Presence 'ID du gestionnaire connecté',
@gestionnaireConnecteID, @procid, 'N' , 'O'
if ( @status = 1 ) goto FinProc

/** Contrôle de la présence du paramètre @gestionnaireConnectePROFIL **/
exec @status=Ctl_Presence 'Profil du gestionnaire connecté',
@gestionnaireConnectePROFIL, @procid, 'N' , 'O'
if ( @status = 1 ) goto FinProc

/** Contrôle de la présence du paramètre @gestionnaireSelectionne **/
exec @status=Ctl_Presence 'ID du gestionnaire selectionné',
@gestionnaireSelectionne, @procid, 'N' , 'O'
if ( @status = 1 ) goto FinProc


/*************************/
/* Corps de la procédure */
/*************************/
-- factures
SET @strRequete1 = 'SELECT distinct MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT,
MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE,
MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vFACTURES.MTT_FACTURE
FROM MEMOS with (nolock)
INNER JOIN CLIENTS with (nolock) ON ([CLIENTS].CO_CLIENT =
MEMOS.CO_CLIENT)
AND CLIENTS.CO_GESTIONNAIRE = '+ cast(@gestionnaireSelectionne as
varchar)
+ ' INNER JOIN vFACTURES with (nolock) ON ([vFACTURES].CO_FACTURE =
MEMOS.CO_FACTURE)
AND vFACTURES.CO_GESTIONNAIRE_CONNECTE = '+cast(@gestionnaireConnecteID
as varchar)
+' AND vFACTURES.PROFIL = '''+@gestionnaireConnectePROFIL+''' '


-- avoirs et trop percus
SET @strRequete2 = 'SELECT distinct MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT,
MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE,
MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vAVOIRS_TROP_PERCUS.MTT_FACTURE
FROM MEMOS
INNER JOIN CLIENTS ON ([CLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND MEMOS.CO_FACTURE is null
AND CLIENTS.CO_GESTIONNAIRE = '+ cast(@gestionnaireSelectionne as
varchar)
+' INNER JOIN vAVOIRS_TROP_PERCUS ON
([vAVOIRS_TROP_PERCUS].CO_AVOIR_TROP_PERCU = MEMOS.CO_AVOIR_TROP_PERCU) AND
vAVOIRS_TROP_PERCUS.CO_GESTIONNAIRE_CONNECTE = '
+cast(@gestionnaireConnecteID as varchar)+' AND vAVOIRS_TROP_PERCUS.PROFIL
= '''+@gestionnaireConnectePROFIL+''' '


-- remboursements
SET @strRequete3 = 'SELECT distinct MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT,
MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE,
MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vREMBOURSEMENTS.MTT_FACTURE
FROM MEMOS
INNER JOIN CLIENTS ON ([CLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND MEMOS.CO_FACTURE is null AND MEMOS.CO_AVOIR_TROP_PERCU is null
AND CLIENTS.CO_GESTIONNAIRE = '+cast(@gestionnaireSelectionne as varchar)
+' INNER JOIN vREMBOURSEMENTS ON
([vREMBOURSEMENTS].CO_REMBOURSEMENT = MEMOS.CO_REMBOURSEMENT)
AND vREMBOURSEMENTS.CO_GESTIONNAIRE_CONNECTE =
'+cast(@gestionnaireConnecteID as varchar)
+'AND vREMBOURSEMENTS.PROFIL = '''+@gestionnaireConnectePROFIL +''' '


SET @strRequete4='SELECT distinct MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT,
MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE,
MEMOS.EMISSION,
vCLIENTS.RAISON_SOCIALE,
0 AS MTT_FACTURE
FROM MEMOS
INNER JOIN vCLIENTS ON ([vCLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND vCLIENTS.CO_GESTIONNAIRE_CONNECTE = '+cast(@gestionnaireConnecteID
as varchar)
+' AND vCLIENTS.PROFIL ='''+ @gestionnaireConnectePROFIL
+''' AND vCLIENTS.CO_GESTIONNAIRE = '+cast(@gestionnaireSelectionne as
varchar)
+' WHERE
MEMOS.CO_FACTURE is null
AND MEMOS.CO_REMBOURSEMENT is null
AND MEMOS.CO_AVOIR_TROP_PERCU is null '


if @operationDateFin is not null and @dateFin is not null
begin
select @sTmp= case @operationDateFin
when '=' then '(MEMOS.DT_FIN ='''+cast(@dateFin as varchar)+''') '
when '&lt;=' then '(MEMOS.DT_FIN &lt;='''+cast(@dateFin as varchar)+''')
'
when '&gt;=' then '(MEMOS.DT_FIN &gt;='''+cast(@dateFin as varchar)+''')
' end
select @strWhere1 = isnull(@strWhere1, ' WHERE ') + @sAnd1 + @sTmp,
@sAnd1 = ' and '
select @strWhere2 = isnull(@strWhere2, ' WHERE ') + @sAnd2 + @sTmp,
@sAnd2 = ' and '
select @strWhere3 = isnull(@strWhere3, ' WHERE ') + @sAnd3 + @sTmp,
@sAnd3 = ' and '
select @strWhere4 = @strWhere4 + @sAnd4 + @sTmp, @sAnd4 = ' and '
end

if @pictogramme IS not NULL
begin
select @sTmp=' MEMOS.CO_TYPE_APPEL = '+cast((@pictogramme +1) as
varchar)+' '
select @strWhere1 = isnull(@strWhere1, ' WHERE ') + @sAnd1 +
@sTmp, @sAnd1 = ' and '
select @strWhere2 = isnull(@strWhere2, ' WHERE ') + @sAnd2 +
@sTmp, @sAnd2 = ' and '
select @strWhere3 = isnull(@strWhere3, ' WHERE ') + @sAnd3 +
@sTmp, @sAnd3 = ' and '
select @strWhere4 = @strWhere4 + @sAnd4 + @sTmp, @sAnd4 = '
and '
end

if @numeroFacture IS not NULL
begin
select @sTmp=' MEMOS.NUMERO_FACTURE LIKE ''%' + @numeroFacture + '%'' '
select @strWhere1 = isnull(@strWhere1, ' WHERE ') + @sAnd1 +
@sTmp, @sAnd1 = ' and '
select @strWhere2 = isnull(@strWhere2, ' WHERE ') + @sAnd2 +
@sTmp, @sAnd2 = ' and '
select @strWhere3 = isnull(@strWhere3, ' WHERE ') + @sAnd3 +
@sTmp, @sAnd3 = ' and '
select @strWhere4 = @strWhere4 + @sAnd4 + @sTmp, @sAnd4 = '
and '
end

if @operationMontant IS not NULL
begin
select @sTmp = case @operationMontant
when '=' then ' = cast('+cast(@montantCreance as
varchar)+ ' as money) '
when '&lt;=' then ' &lt;= cast('+cast(@montantCreance
as varchar)+ ' as money) '
when '&gt;=' then ' &gt;= cast('+cast(@montantCreance
as varchar)+ ' as money) ' end

select @strWhere1 = isnull(@strWhere1, ' WHERE ') + @sAnd1 + '
vFACTURES.MTT_FACTURE '+ @sTmp, @sAnd1 = ' and '
select @strWhere2 = isnull(@strWhere2, ' WHERE ') + @sAnd2 + '
vAVOIRS_TROP_PERCUS.MTT_FACTURE '+ @sTmp, @sAnd2 = ' and '
select @strWhere3 = isnull(@strWhere3, ' WHERE ') + @sAnd3 + '
vREMBOURSEMENTS.MTT_FACTURE '+ @sTmp, @sAnd3 = ' and '
end

select @strRequete = @strRequete1 + isnull(@strWhere1,' ') +' UNION
'+@strRequete2 + isnull(@strWhere2,' ') +' UNION '+@strRequete3 +
isnull(@strWhere3,' ') +' UNION '+@strRequete4 + @strWhere4 +' ORDER BY
CO_MEMO;'

EXEC (@strRequete)

/******************************/
/* Controle de l'intruction */
/******************************/
exec @status=CONTROLE_DSM @procid, @@error, @@rowcount, 'N' , 'O' ,
@nbMaxEnregistrements,
@gestionnaireConnecteID,
@gestionnaireConnectePROFIL,
@gestionnaireSelectionne,
@dateFin,
@operationDateFin,
@operationDateFin,
@operationMontant,
@pictogramme,
@numeroFacture


/* Verifie si la procedure de controle a detecte une erreur */
if ( @status = 1 ) goto FinProc

/*************************************/
/* Fin de la procédure stockée */
/*************************************/

FinProc:
/*************************************************************************************************/
/* Gestion des erreurs :
*/
/* ---------------------
*/
/* La variable @status permet d'indiquer, a la procedure appelante
(SFL), l'etat */
/* dans lequel la procedure SDO s'est terminee.
*/
/* Cette variable peut avoir l'une des valeurs suivantes :
*/
/* 0 : procedure terminee sans erreur
*/
/* 1 : procedure en echec (une erreur a ete detectee)
*/
/* 2 : valeur indiquant qu'aucune occurence n'a ete trouve (SDO de
selection) */
/**************************************************************************************************/

set rowcount 0
return @status
set nocount off
END






--
-- STR REQUETE CONTIENDRAIT PAR EXEMPLE
--
SELECT DISTINCT
MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT, MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE, MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vFACTURES.MTT_FACTURE
FROM
MEMOS with (nolock)
INNER JOIN CLIENTS with (nolock)
ON ([CLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND CLIENTS.CO_GESTIONNAIRE = 1112
INNER JOIN vFACTURES with (nolock)
ON ([vFACTURES].CO_FACTURE = MEMOS.CO_FACTURE)
AND vFACTURES.CO_GESTIONNAIRE_CONNECTE = 1111
AND vFACTURES.PROFIL = 'Bourriquet'
WHERE
(MEMOS.DT_FIN ='28/09/2007 23:08:15') and
MEMOS.CO_TYPE_APPEL = 2 and
MEMOS.NUMERO_FACTURE LIKE '%FAC00047991A%' and
vFACTURES.MTT_FACTURE = 1000
UNION
SELECT DISTINCT
MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT, MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE, MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vAVOIRS_TROP_PERCUS.MTT_FACTURE
FROM
MEMOS
INNER JOIN CLIENTS
ON ([CLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND MEMOS.CO_FACTURE is null
AND CLIENTS.CO_GESTIONNAIRE = 1112
INNER JOIN vAVOIRS_TROP_PERCUS
ON ([vAVOIRS_TROP_PERCUS].CO_AVOIR_TROP_PERCU = MEMOS.CO_AVOIR_TROP_PERCU)
AND vAVOIRS_TROP_PERCUS.CO_GESTIONNAIRE_CONNECTE = 1111
AND vAVOIRS_TROP_PERCUS.PROFIL = 'Bourriquet'
WHERE
(MEMOS.DT_FIN ='28/09/2007 23:08:15') and
MEMOS.CO_TYPE_APPEL = 2 and
MEMOS.NUMERO_FACTURE LIKE '%FAC00047991A%' and
vAVOIRS_TROP_PERCUS.MTT_FACTURE = 1000
UNION
SELECT DISTINCT
MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT, MEMOS.DT_DEBUT,
MEMOS.DT_FIN, MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE, MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vREMBOURSEMENTS.MTT_FACTURE
FROM
MEMOS
INNER JOIN CLIENTS
ON ([CLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND MEMOS.CO_FACTURE is null
AND MEMOS.CO_AVOIR_TROP_PERCU is null
AND CLIENTS.CO_GESTIONNAIRE = 1112
INNER JOIN vREMBOURSEMENTS
ON ([vREMBOURSEMENTS].CO_REMBOURSEMENT = MEMOS.CO_REMBOURSEMENT)
AND vREMBOURSEMENTS.CO_GESTIONNAIRE_CONNECTE = 1111
AND vREMBOURSEMENTS.PROFIL = 'Bourriquet'
WHERE
(MEMOS.DT_FIN ='28/09/2007 23:08:15') and
MEMOS.CO_TYPE_APPEL = 2 and
MEMOS.NUMERO_FACTURE LIKE '%FAC00047991A%' and
vREMBOURSEMENTS.MTT_FACTURE = 1000
UNION
SELECT DISTINCT
MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT,
MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE, MEMOS.EMISSION,
vCLIENTS.RAISON_SOCIALE,
0 AS MTT_FACTURE
FROM
MEMOS
INNER JOIN vCLIENTS
ON ([vCLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND vCLIENTS.CO_GESTIONNAIRE_CONNECTE = 1111
AND vCLIENTS.PROFIL ='Bourriquet'
AND vCLIENTS.CO_GESTIONNAIRE = 1112
WHERE
MEMOS.CO_FACTURE is null AND
MEMOS.CO_REMBOURSEMENT is null AND
MEMOS.CO_AVOIR_TROP_PERCU is null AND (MEMOS.DT_FIN ='28/09/2007
23:08:15') and
MEMOS.CO_TYPE_APPEL = 2 and
MEMOS.NUMERO_FACTURE LIKE '%FAC00047991A%'
ORDER BY CO_MEMO;

4 réponses

Avatar
Philippe TROTIN [MS]
Bonjour,

1. Il ne faut pas écrire @montanMin=NULL mais @montanMin IS NULL car sinon
cela ne fonctionnera pas.

2. Si on construit une chaine pour faire du SQL dynamique, il est préférable
d'utiliser sp_executesql :

SET @MaChaine = N'SELECT id , montant FROM MaTable WHERE montant<= @Param1
ORDER BY montant'
SET @MesParametres = N'@Param1 int)
EXEC sp_executesql @MaChaine, @MesParametres, @Param1

3. Il est toujours préférable pour des raisons de performance et de
maintenabilité de laisser à chaque langage le travail qu'il sait faire le
mieux. Maintenant c'est toujours un compromis entre complexité et
lisibilité.

Bon courage.

Cordialement
_______________________________

Philippe TROTIN
Microsoft Services France
_______________________________

"Jean BONBEUR" a écrit dans le message de groupe de
discussion : bqoLi.35$
bonjour, dans le cadre d'un projet web pour un client, nous utilisons des
store proc, et j'aimerais avoir votre avi par rapport aux performances
entre deux façons de l'implanter.
la proc à pour objectif de faire un SELECT, et le client choisi dans une
fenetre des criteres de filtrage. il ne saisit pas de SQL, c'est juste
deux ou trois textbox dans lequelles on saisi des valeurs. si il y'a une
valeur, le critere s'applique, sinon, il ne s'applique pas. on transfert
dans la storeproc par des param, et si un param est null, le critere
s'applique, sinon, il ne s'applique pas.

un exemple simple avec @montanMin et @montantMax :

SELECT id , montant WHERE ( @montanMin=NULL OR @montanMin<=montant ) AND
( @montantMax=NULL OR montant<=@montantMax ) ORDER BY montant ASC

une deuxime technique consiste à construire le SQL dans une chaine de
caractere, et à l'executer avec la commande EXEC

un appel à la proc avec @montanMin = NULL et @montantMax = 500 donnerait :

@sql = ...
-- @sql contient SELECT id , montant WHERE AND montant<P0 ORDER BY
montant ASC
EXEC (@sql)

maintenant, sachant que des indexs sont posés sur montant, quelle est la
solution qui va produire les meilleurs temps de réponse ? EXEC fabrique
t'il un plan d'execution from scratch qui soit assez efficace ?
l'optimiseur sait il optimiser la proc 1 en quelque chose du style :

if(@montanMin IS NULL)
if(@montantMax IS NULL)
SELECT id , montant ORDER BY montant ASC
else
SELECT id , montant WHERE montant<=@montantMax ORDER BY montant ASC
else
if(@montantMax IS NULL)
SELECT id , montant WHERE @montanMin<=montant ORDER BY montant ASC
else
SELECT id , montant WHERE @montanMin<=montant AND
montant<=@montantMax ORDER BY montant ASC


comment puis-je évaluer la complexité d'une requete qui va etre appellée
dans EXEC(@sql) au sein d'une store proc ? est-ce que c'est pareil en
perfs de faire EXEC @sql, et de construire du SQL côté appli, et
l'executer au moyen d'une DbCommand. si c'est le cas, tant mieux, le sql
dans du sql, c'est illisible, pas debbugable, etc etc...

maintenant, voici le cas réel qui me préoccupe, suivi d'un exemple de ce
que contient @strRequete qui va passer dans l'exec : ça constuit 4
SELECT qu'on UNION, et dont on ORDER BY le résultat.
outre la différence entre les deux methodes, voyez vous des choses qui
sont des enormités, des oublis, des problemes éventuels ?

merci d'avance pour votre aide, j'en ai sacrément besoin...


Frédéric





CREATE Proc dbo.dsm_Memo_ChargerMemo
(
@nbMaxEnregistrements int,
@gestionnaireConnecteID int,
@gestionnaireConnectePROFIL varchar(4),
@gestionnaireSelectionne int,
@dateFin datetime = null,
@operationDateFin varchar(2) = null,
@montantCreance money = null,
@operationMontant varchar(2) = null,
@pictogramme int = null,
@numeroFacture varchar(50) = null
)
AS
BEGIN
/******************/
/* Initialisation */
/******************/
set nocount on
set rowcount @nbMaxEnregistrements

/** Déclaration des variables indispensables au traitement **/
declare @procid int, /* Identifiant de la proc */
@status int, /* Gestion d'erreur */
@strRequete varchar(8000),
@strRequete1 varchar(8000),
@strRequete2 varchar(8000),
@strRequete3 varchar(8000),
@strRequete4 varchar(8000),
@strWhere1 varchar(8000),
@strWhere2 varchar(8000),
@strWhere3 varchar(8000),
@strWhere4 varchar(8000),
@sAnd1 char(4),
@sAnd2 char(4),
@sAnd3 char(4),
@sAnd4 char(4),
@sTmp varchar(1000)

/** Initialisation des variables utilisees dans les controles d'erreurs
**/
select @procid = @@procid,
@status = 0,
@sAnd1 = '',
@sAnd3 = '',
@sAnd2 = '',
@sAnd4 = ' AND ',
@strWhere1=null,
@strWhere2=null,
@strWhere3=null,
@strWhere4=' '

/***************************************************/
/* Vérification de la validité des paramètres */
/***************************************************/

/** Contrôle de la présence du paramètre @nbMaxEnregistrements **/
exec @status=Ctl_Presence 'Nombre maximal d enregistrements a retourner',
@nbMaxEnregistrements, @procid, 'N' , 'O'
if ( @status = 1 ) goto FinProc

/** Contrôle de la présence du paramètre @gestionnaireConnecteID **/
exec @status=Ctl_Presence 'ID du gestionnaire connecté',
@gestionnaireConnecteID, @procid, 'N' , 'O'
if ( @status = 1 ) goto FinProc

/** Contrôle de la présence du paramètre @gestionnaireConnectePROFIL **/
exec @status=Ctl_Presence 'Profil du gestionnaire connecté',
@gestionnaireConnectePROFIL, @procid, 'N' , 'O'
if ( @status = 1 ) goto FinProc

/** Contrôle de la présence du paramètre @gestionnaireSelectionne **/
exec @status=Ctl_Presence 'ID du gestionnaire selectionné',
@gestionnaireSelectionne, @procid, 'N' , 'O'
if ( @status = 1 ) goto FinProc


/*************************/
/* Corps de la procédure */
/*************************/
-- factures
SET @strRequete1 = 'SELECT distinct MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT,
MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE,
MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vFACTURES.MTT_FACTURE
FROM MEMOS with (nolock)
INNER JOIN CLIENTS with (nolock) ON ([CLIENTS].CO_CLIENT =
MEMOS.CO_CLIENT)
AND CLIENTS.CO_GESTIONNAIRE = '+ cast(@gestionnaireSelectionne as
varchar)
+ ' INNER JOIN vFACTURES with (nolock) ON ([vFACTURES].CO_FACTURE =
MEMOS.CO_FACTURE)
AND vFACTURES.CO_GESTIONNAIRE_CONNECTE = '+cast(@gestionnaireConnecteID
as varchar)
+' AND vFACTURES.PROFIL = '''+@gestionnaireConnectePROFIL+''' '


-- avoirs et trop percus
SET @strRequete2 = 'SELECT distinct MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT,
MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE,
MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vAVOIRS_TROP_PERCUS.MTT_FACTURE
FROM MEMOS
INNER JOIN CLIENTS ON ([CLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND MEMOS.CO_FACTURE is null
AND CLIENTS.CO_GESTIONNAIRE = '+ cast(@gestionnaireSelectionne as
varchar)
+' INNER JOIN vAVOIRS_TROP_PERCUS ON
([vAVOIRS_TROP_PERCUS].CO_AVOIR_TROP_PERCU = MEMOS.CO_AVOIR_TROP_PERCU)
AND vAVOIRS_TROP_PERCUS.CO_GESTIONNAIRE_CONNECTE = '
+cast(@gestionnaireConnecteID as varchar)+' AND vAVOIRS_TROP_PERCUS.PROFIL
= '''+@gestionnaireConnectePROFIL+''' '


-- remboursements
SET @strRequete3 = 'SELECT distinct MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT,
MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE,
MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vREMBOURSEMENTS.MTT_FACTURE
FROM MEMOS
INNER JOIN CLIENTS ON ([CLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND MEMOS.CO_FACTURE is null AND MEMOS.CO_AVOIR_TROP_PERCU is null
AND CLIENTS.CO_GESTIONNAIRE = '+cast(@gestionnaireSelectionne as
varchar)
+' INNER JOIN vREMBOURSEMENTS ON
([vREMBOURSEMENTS].CO_REMBOURSEMENT = MEMOS.CO_REMBOURSEMENT)
AND vREMBOURSEMENTS.CO_GESTIONNAIRE_CONNECTE =
'+cast(@gestionnaireConnecteID as varchar)
+'AND vREMBOURSEMENTS.PROFIL = '''+@gestionnaireConnectePROFIL +''' '


SET @strRequete4='SELECT distinct MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT,
MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE,
MEMOS.EMISSION,
vCLIENTS.RAISON_SOCIALE,
0 AS MTT_FACTURE
FROM MEMOS
INNER JOIN vCLIENTS ON ([vCLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND vCLIENTS.CO_GESTIONNAIRE_CONNECTE = '+cast(@gestionnaireConnecteID
as varchar)
+' AND vCLIENTS.PROFIL ='''+ @gestionnaireConnectePROFIL
+''' AND vCLIENTS.CO_GESTIONNAIRE = '+cast(@gestionnaireSelectionne
as varchar)
+' WHERE
MEMOS.CO_FACTURE is null
AND MEMOS.CO_REMBOURSEMENT is null
AND MEMOS.CO_AVOIR_TROP_PERCU is null '


if @operationDateFin is not null and @dateFin is not null
begin
select @sTmp= case @operationDateFin
when '=' then '(MEMOS.DT_FIN ='''+cast(@dateFin as varchar)+''') '
when '&lt;=' then '(MEMOS.DT_FIN &lt;='''+cast(@dateFin as
varchar)+''') '
when '&gt;=' then '(MEMOS.DT_FIN &gt;='''+cast(@dateFin as
varchar)+''') ' end
select @strWhere1 = isnull(@strWhere1, ' WHERE ') + @sAnd1 + @sTmp,
@sAnd1 = ' and '
select @strWhere2 = isnull(@strWhere2, ' WHERE ') + @sAnd2 + @sTmp,
@sAnd2 = ' and '
select @strWhere3 = isnull(@strWhere3, ' WHERE ') + @sAnd3 + @sTmp,
@sAnd3 = ' and '
select @strWhere4 = @strWhere4 + @sAnd4 + @sTmp, @sAnd4 = ' and '
end

if @pictogramme IS not NULL
begin
select @sTmp=' MEMOS.CO_TYPE_APPEL = '+cast((@pictogramme +1) as
varchar)+' '
select @strWhere1 = isnull(@strWhere1, ' WHERE ') + @sAnd1 +
@sTmp, @sAnd1 = ' and '
select @strWhere2 = isnull(@strWhere2, ' WHERE ') + @sAnd2 +
@sTmp, @sAnd2 = ' and '
select @strWhere3 = isnull(@strWhere3, ' WHERE ') + @sAnd3 +
@sTmp, @sAnd3 = ' and '
select @strWhere4 = @strWhere4 + @sAnd4 + @sTmp, @sAnd4 = '
and '
end

if @numeroFacture IS not NULL
begin
select @sTmp=' MEMOS.NUMERO_FACTURE LIKE ''%' + @numeroFacture + '%'' '
select @strWhere1 = isnull(@strWhere1, ' WHERE ') + @sAnd1 +
@sTmp, @sAnd1 = ' and '
select @strWhere2 = isnull(@strWhere2, ' WHERE ') + @sAnd2 +
@sTmp, @sAnd2 = ' and '
select @strWhere3 = isnull(@strWhere3, ' WHERE ') + @sAnd3 +
@sTmp, @sAnd3 = ' and '
select @strWhere4 = @strWhere4 + @sAnd4 + @sTmp, @sAnd4 = '
and '
end

if @operationMontant IS not NULL
begin
select @sTmp = case @operationMontant
when '=' then ' = cast('+cast(@montantCreance as
varchar)+ ' as money) '
when '&lt;=' then ' &lt;= cast('+cast(@montantCreance
as varchar)+ ' as money) '
when '&gt;=' then ' &gt;= cast('+cast(@montantCreance
as varchar)+ ' as money) ' end

select @strWhere1 = isnull(@strWhere1, ' WHERE ') + @sAnd1 +
' vFACTURES.MTT_FACTURE '+ @sTmp, @sAnd1 = ' and '
select @strWhere2 = isnull(@strWhere2, ' WHERE ') + @sAnd2 +
' vAVOIRS_TROP_PERCUS.MTT_FACTURE '+ @sTmp, @sAnd2 = ' and '
select @strWhere3 = isnull(@strWhere3, ' WHERE ') + @sAnd3 +
' vREMBOURSEMENTS.MTT_FACTURE '+ @sTmp, @sAnd3 = ' and '
end

select @strRequete = @strRequete1 + isnull(@strWhere1,' ') +' UNION
'+@strRequete2 + isnull(@strWhere2,' ') +' UNION '+@strRequete3 +
isnull(@strWhere3,' ') +' UNION '+@strRequete4 + @strWhere4 +' ORDER BY
CO_MEMO;'

EXEC (@strRequete)

/******************************/
/* Controle de l'intruction */
/******************************/
exec @status=CONTROLE_DSM @procid, @@error, @@rowcount, 'N' , 'O' ,
@nbMaxEnregistrements,
@gestionnaireConnecteID,
@gestionnaireConnectePROFIL,
@gestionnaireSelectionne,
@dateFin,
@operationDateFin,
@operationDateFin,
@operationMontant,
@pictogramme,
@numeroFacture


/* Verifie si la procedure de controle a detecte une erreur */
if ( @status = 1 ) goto FinProc

/*************************************/
/* Fin de la procédure stockée */
/*************************************/

FinProc:

/*************************************************************************************************/
/* Gestion des erreurs : */
/* --------------------- */
/* La variable @status permet d'indiquer, a la procedure appelante
(SFL), l'etat */
/* dans lequel la procedure SDO s'est terminee. */
/* Cette variable peut avoir l'une des valeurs suivantes : */
/* 0 : procedure terminee sans erreur */
/* 1 : procedure en echec (une erreur a ete detectee) */
/* 2 : valeur indiquant qu'aucune occurence n'a ete trouve (SDO
de selection) */

/**************************************************************************************************/

set rowcount 0
return @status
set nocount off
END






--
-- STR REQUETE CONTIENDRAIT PAR EXEMPLE
--
SELECT DISTINCT
MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT, MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE, MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vFACTURES.MTT_FACTURE
FROM
MEMOS with (nolock)
INNER JOIN CLIENTS with (nolock)
ON ([CLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND CLIENTS.CO_GESTIONNAIRE = 1112
INNER JOIN vFACTURES with (nolock)
ON ([vFACTURES].CO_FACTURE = MEMOS.CO_FACTURE)
AND vFACTURES.CO_GESTIONNAIRE_CONNECTE = 1111
AND vFACTURES.PROFIL = 'Bourriquet'
WHERE
(MEMOS.DT_FIN ='28/09/2007 23:08:15') and
MEMOS.CO_TYPE_APPEL = 2 and
MEMOS.NUMERO_FACTURE LIKE '%FAC00047991A%' and
vFACTURES.MTT_FACTURE = 1000
UNION
SELECT DISTINCT
MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT, MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE, MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vAVOIRS_TROP_PERCUS.MTT_FACTURE
FROM
MEMOS
INNER JOIN CLIENTS
ON ([CLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND MEMOS.CO_FACTURE is null
AND CLIENTS.CO_GESTIONNAIRE = 1112
INNER JOIN vAVOIRS_TROP_PERCUS
ON ([vAVOIRS_TROP_PERCUS].CO_AVOIR_TROP_PERCU = MEMOS.CO_AVOIR_TROP_PERCU)
AND vAVOIRS_TROP_PERCUS.CO_GESTIONNAIRE_CONNECTE = 1111
AND vAVOIRS_TROP_PERCUS.PROFIL = 'Bourriquet'
WHERE
(MEMOS.DT_FIN ='28/09/2007 23:08:15') and
MEMOS.CO_TYPE_APPEL = 2 and
MEMOS.NUMERO_FACTURE LIKE '%FAC00047991A%' and
vAVOIRS_TROP_PERCUS.MTT_FACTURE = 1000
UNION
SELECT DISTINCT
MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT, MEMOS.DT_DEBUT,
MEMOS.DT_FIN, MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE, MEMOS.EMISSION,
CLIENTS.RAISON_SOCIALE,
vREMBOURSEMENTS.MTT_FACTURE
FROM
MEMOS
INNER JOIN CLIENTS
ON ([CLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND MEMOS.CO_FACTURE is null
AND MEMOS.CO_AVOIR_TROP_PERCU is null
AND CLIENTS.CO_GESTIONNAIRE = 1112
INNER JOIN vREMBOURSEMENTS
ON ([vREMBOURSEMENTS].CO_REMBOURSEMENT = MEMOS.CO_REMBOURSEMENT)
AND vREMBOURSEMENTS.CO_GESTIONNAIRE_CONNECTE = 1111
AND vREMBOURSEMENTS.PROFIL = 'Bourriquet'
WHERE
(MEMOS.DT_FIN ='28/09/2007 23:08:15') and
MEMOS.CO_TYPE_APPEL = 2 and
MEMOS.NUMERO_FACTURE LIKE '%FAC00047991A%' and
vREMBOURSEMENTS.MTT_FACTURE = 1000
UNION
SELECT DISTINCT
MEMOS.CO_MEMO,
MEMOS.CO_FACTURE AS CO_FACTURE,
MEMOS.CO_REMBOURSEMENT AS CO_REMBOURSEMENT,
MEMOS.CO_AVOIR_TROP_PERCU AS CO_AVOIR_TROP_PERCU,
MEMOS.CO_CLIENT AS CO_CLIENT,
MEMOS.DT_DEBUT,
MEMOS.DT_FIN,
MEMOS.INTITULE,
MEMOS.NUMERO_FACTURE AS NUMERO_FACTURE,
MEMOS.CO_TYPE_APPEL AS CO_TYPE_APPEL,
MEMOS.TRAITE, MEMOS.EMISSION,
vCLIENTS.RAISON_SOCIALE,
0 AS MTT_FACTURE
FROM
MEMOS
INNER JOIN vCLIENTS
ON ([vCLIENTS].CO_CLIENT = MEMOS.CO_CLIENT)
AND vCLIENTS.CO_GESTIONNAIRE_CONNECTE = 1111
AND vCLIENTS.PROFIL ='Bourriquet'
AND vCLIENTS.CO_GESTIONNAIRE = 1112
WHERE
MEMOS.CO_FACTURE is null AND
MEMOS.CO_REMBOURSEMENT is null AND
MEMOS.CO_AVOIR_TROP_PERCU is null AND (MEMOS.DT_FIN ='28/09/2007
23:08:15') and
MEMOS.CO_TYPE_APPEL = 2 and
MEMOS.NUMERO_FACTURE LIKE '%FAC00047991A%'
ORDER BY CO_MEMO;




Avatar
Jean BONBEUR
> 1. Il ne faut pas écrire @montanMin=NULL mais @montanMin IS NULL car
sinon cela ne fonctionnera pas.



ok. abus de langage. désolé

2. Si on construit une chaine pour faire du SQL dynamique, il est
préférable d'utiliser sp_executesql :

SET @MaChaine = N'SELECT id , montant FROM MaTable WHERE montant<= @Param1
ORDER BY montant'
SET @MesParametres = N'@Param1 int)
EXEC sp_executesql @MaChaine, @MesParametres, @Param1



ok. c'est rapport au plan d'execution, ou pour une tout autre raison ?

3. Il est toujours préférable pour des raisons de performance et de
maintenabilité de laisser à chaque langage le travail qu'il sait faire le
mieux. Maintenant c'est toujours un compromis entre complexité et
lisibilité.



arf... je ferais bien une classe SqlWriter, et j'enverrais la commande dans
un SqlCommand, mais l'ennui, c'est que je ne sais pas évaluer avec précision
la perf de chacun des choix... du SQL qui arrive par ADO .Net est il
optimisé par un plan from scratch ? cela prend il plus de temps que le
calcul de la requete elle même (vu la requete, j'en doute, mais bon)... EXEC
(@text) produit elle un plan d'optimisation ?

je suis en train d'essayer une technique de "déballage" combinatoire, ou
l'on spécifie les morceaux dans un xml, et ou un xsl fabrique le sql éclaté
en 2^n cas. est-ce bien utile ?

merci de votre aide.
Avatar
Philippe TROTIN [MS]
Bonjour,

2. Oui. Le fait de passer les variables SQL en paramètre d'un sp_executesql
va permettre de cacher le plan d'exécution ce qui n'est pas le cas si on ne
variabilise pas.

3. Pensez au pauvre DBA qui va devoir un jour faire évoluer le modèle de
données ou optimiser les requêtes pour des raisons de performances. Le mieux
reste toujours la procédure stockées ou la construction de la chaine sql
dynamique dans une procédure stockée. Mais ce n'est que mon avis... :-)

Cordialement
_______________________________

Philippe TROTIN
Microsoft Services France
_______________________________

"Jean BONBEUR" a écrit dans le message de groupe de
discussion : VsbMi.151$
1. Il ne faut pas écrire @montanMin=NULL mais @montanMin IS NULL car
sinon cela ne fonctionnera pas.



ok. abus de langage. désolé

2. Si on construit une chaine pour faire du SQL dynamique, il est
préférable d'utiliser sp_executesql :

SET @MaChaine = N'SELECT id , montant FROM MaTable WHERE montant<=
@Param1 ORDER BY montant'
SET @MesParametres = N'@Param1 int)
EXEC sp_executesql @MaChaine, @MesParametres, @Param1



ok. c'est rapport au plan d'execution, ou pour une tout autre raison ?

3. Il est toujours préférable pour des raisons de performance et de
maintenabilité de laisser à chaque langage le travail qu'il sait faire le
mieux. Maintenant c'est toujours un compromis entre complexité et
lisibilité.



arf... je ferais bien une classe SqlWriter, et j'enverrais la commande
dans un SqlCommand, mais l'ennui, c'est que je ne sais pas évaluer avec
précision la perf de chacun des choix... du SQL qui arrive par ADO .Net
est il optimisé par un plan from scratch ? cela prend il plus de temps que
le calcul de la requete elle même (vu la requete, j'en doute, mais bon)...
EXEC (@text) produit elle un plan d'optimisation ?

je suis en train d'essayer une technique de "déballage" combinatoire, ou
l'on spécifie les morceaux dans un xml, et ou un xsl fabrique le sql
éclaté en 2^n cas. est-ce bien utile ?

merci de votre aide.



Avatar
Jean BONBEUR
> 2. Oui. Le fait de passer les variables SQL en paramètre d'un
sp_executesql va permettre de cacher le plan d'exécution ce qui n'est pas
le cas si on ne variabilise pas.



ok, je se savais pas.

3. Pensez au pauvre DBA qui va devoir un jour faire évoluer le modèle de
données ou optimiser les requêtes pour des raisons de performances. Le
mieux reste toujours la procédure stockées ou la construction de la chaine
sql dynamique dans une procédure stockée. Mais ce n'est que mon avis...
:-)



si on considere que la couche donnée se limite à SQLServer, oui.

ma (petite) experimentation suggere d'utiliser une SqlCommand coté client :
ça conduit à des résultats meilleurs. le déballage combinatoire est
excellent, mais pas significativement plus que le côté client... ça permet
aussi de déporter certains traitements sur le server applicatif, et vu qu'on
sait demultiplier les servers applicatif, mais pas le SGBD, c'est pas mal...
donc, à voir...

merci pour votre aide

--
Frédéric DIDIER
SQLI Montpellier