Question

J'ai écrit une procédure stockée de recherche paginée à l'aide de SQL Server 2005. Elle nécessite plusieurs paramètres et les critères de recherche sont moyennement complexes.

En raison de l'architecture frontale, je dois pouvoir renvoyer le nombre de résultats qui seraient renvoyés sans renvoyer les résultats. Le client appelle ensuite la procédure stockée une seconde fois pour obtenir les résultats réels.

D'un côté, je peux écrire deux procédures stockées - une pour gérer le nombre et l'autre pour gérer les données réelles, mais je dois ensuite conserver la logique de recherche à au moins deux endroits différents. Alternativement, je peux écrire la procédure stockée de telle sorte qu'elle prenne un paramètre de bit et soit je retourne des données, soit juste un compte. Peut-être remplissez-vous une table temporaire avec les données et si le décompte ne fait que compter, sinon sélectionnez-le. Le problème ici est que le processus de comptage pourrait être optimisé, de sorte qu'il semble y avoir beaucoup de frais généraux supplémentaires (il faut obtenir des colonnes inutiles, etc.). En outre, l’utilisation de ce type de logique dans une procédure stockée peut entraîner des plans de requête incorrects lorsqu’elle va et vient entre les deux utilisations.

La quantité de données dans le système n’est pas trop élevée (seulement quelques millions de lignes pour les plus grandes tables). Cependant, il peut y avoir beaucoup d'utilisateurs simultanés.

Que pensent les gens de ces approches? Quelqu'un a-t-il déjà résolu ce problème d'une manière que je n'avais pas envisagée?

Ils NE PEUVENT PAS prendre les résultats et compter en même temps à partir d'un seul appel.

Merci!

Était-ce utile?

La solution

Personnellement, je préfère l’approche à deux requêtes. Certes, vous devez maintenir la logique de recherche à deux endroits, mais j’ai constaté que l’optimisation des performances et la netteté globale du code sont payantes à la fin.

L'utilisation d'un indicateur passé à une procédure unique est une solution potentielle, mais je trouve cela très difficile à maintenir, en particulier pour la logique de recherche complexe.

La voie d'utilisation des tables temporaires, etc., qui ajoute simplement beaucoup plus de temps système que nécessaire.

Ainsi, pourquoi j’ai atterri avec la méthode des deux requêtes. Tout ce que je trouve en ligne recommande également cette approche.

Autres conseils

Ce n'est pas un problème normal et vous voulez généralement que le total compte en même temps que vous obteniez une page.

Cela dit, utilisez deux procédures différentes. La raison en est que vous avez deux actions très différentes qui ne se ressemblent que superficiellement.

Je suis sûr que vous avez pris en compte ceci: si les données changent le nombre et que toute pagination ultérieure peut être différente (si des lignes sont ajoutées / supprimées)

Vous pouvez avoir une fonction définie par l'utilisateur qui renvoie les PK des lignes correspondantes, ce qui est relativement facile à faire

SELECT COUNT(*) FROM dbo.MyQueryFunction(@Param1, @Param2)

pour obtenir le compte, puis

SELECT Col1, Col2, ...
FROM dbo.MyQueryFunction(@Param1, @Param2) AS FN
     JOIN dbo.MyTable AS T
         ON T.ID = FN.ID
     ... more JOINs ...

pour obtenir les données.

Je ne sais pas si cela convient à Row_Number pour la pagination suivante, mais cela conserverait la "logique de requête" actuelle. contenu dans MyQueryFunction - vous aurez toujours les doublons de toutes les colonnes à récupérer, dans le Sproc et la fonction.

Cela ne vous aidera peut-être pas à résoudre votre problème spécifique, mais SQL 2005 introduit la fonction Row_Number, très utile pour le contrôle de la pagination

Exemple de numéro de ligne

Beaucoup plus facile que les tables temporaires.

J'ai trouvé ce fil à la recherche de quelque chose d'autre et je pensais qu'il était possible de renvoyer le jeu de résultats et le nombre d'enregistrements avec une seule requête. Vous avez juste besoin d'un paramètre 'out' pour porter la valeur. Ci-dessous, un copier / coller d’un exemple Oracle, mais la technique est très similaire pour SQL Server (je n’ai pas accès à l’atmosphère de SQL Server).

Le gros problème avec SQL Server est que vous devrez peut-être utiliser row_number () vs rownum.

procedure get_sample_results (
    startrow in number default 1,
    numberofrows in number default 10,
    whereclause in varchar2,
    matchingrows out number,
    rc  out sys_refcursor
)
is
    stmnt varchar2(5000);
    endrow number;
begin

    stmnt := stmnt || 'select * from table t where 1=1';
    if whereclause is not null then
        stmnt := stmnt || ' and ' || whereclause;
    end if;

    execute immediate 'select count(*) from (' || stmnt || ')' into matchingrows;

    stmnt := 'select * from (' || stmnt || ') where rownum between :1 and :2';        

    -- must subtract one to compenstate for the inclusive between clause
    endrow := startrow + numberofrows - 1;
    open rc for stmnt using startrow, endrow;

end get_sample_results;

Je connais une vieille question (qui a déjà été marquée), mais vous pouvez renvoyer un jeu d'enregistrements (alias les résultats) ET avoir une valeur de sortie (ou plusieurs sorties), ce qui signifie que vous n'avez besoin que d'un aller-retour pour la base de données. .

C’est quelque chose que je réfléchis à voix haute (et c’est plus tard que mon heure de coucher est passée ...)

CREATE PROCEDURE WhatEver
(
   @SomeParam1 NVARCHAR(200),
   ....
   @SomeParam_X INT,
   @NumberOfResults INTEGER OUTPUT
)
BEGIN
    SET NOCOUNT ON

    -- Do your search stuff.
    -- ....
    SELECT Whatever
    FROM WhatWhat
    ...

    -- Ok, the results/recordset has been sent prepared.
    -- Now the rowcount
    SET @NumberOfResults = @@ROWCOUNT
END

HTH.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top