Domanda

Ho scritto una procedura memorizzata di ricerca paginata utilizzando SQL Server 2005. Sono necessari numerosi parametri e i criteri di ricerca sono moderatamente complessi.

A causa dell'architettura front-end, devo essere in grado di restituire il numero di risultati che tornerebbero senza effettivamente restituire i risultati. Il front-end chiamerebbe quindi la procedura memorizzata una seconda volta per ottenere i risultati effettivi.

Da un lato posso scrivere due procedure memorizzate: una per gestire il conteggio e una per gestire i dati effettivi, ma poi devo mantenere la logica di ricerca in almeno due posti diversi. In alternativa, posso scrivere la procedura memorizzata in modo che richieda un parametro bit e in base a ciò restituisco i dati o solo un conteggio. Forse riempire una tabella temporanea con i dati e se il conteggio fa solo un conteggio da quello, altrimenti fare una selezione da esso. Il problema qui è che il processo di conteggio potrebbe essere ottimizzato in modo che ci sia un sacco di sovraccarico in più sembra (devi ottenere colonne non necessarie, ecc.). Inoltre, l'utilizzo di questo tipo di logica in una procedura memorizzata potrebbe comportare piani di query errati poiché va avanti e indietro tra i due usi.

La quantità di dati nel sistema non è troppo elevata (solo un paio di milioni di righe anche per le tabelle più grandi). Tuttavia, potrebbero esserci molti utenti simultanei.

Quali sono i pensieri delle persone su questi approcci? Qualcuno ha già risolto questo problema in un modo a cui non avevo pensato?

Loro NON POSSONO prendere i risultati e contare allo stesso tempo da una singola chiamata.

Grazie!

È stato utile?

Soluzione

Vado personalmente con l'approccio a due query, sì, devi mantenere la logica di ricerca in due punti, ma ho scoperto che il vantaggio dell'ottimizzazione delle prestazioni e la pulizia generale del codice alla fine pagano.

L'uso di un flag passato a una singola procedura è una soluzione potenziale, ma trovo molto difficile mantenerlo, soprattutto per la logica di ricerca complessa.

Il percorso di utilizzo di tabelle temporanee, ecc., che aggiunge MODO più sovraccarico di quanto necessario.

Quindi, perché sono arrivato al metodo delle due query. Tutto ciò che trovo online raccomanda anche questo approccio.

Altri suggerimenti

Questo non è un problema normale e di solito vuoi il conteggio totale mentre ottieni una pagina.

Detto questo, utilizzare due diverse procedure. Il motivo è che hai due azioni molto diverse che si assomigliano solo superficialmente.

Sono sicuro che hai considerato questo: se i dati cambiano il COUNT e qualsiasi successivo Paging effettivo potrebbe essere diverso (se le righe sono state aggiunte / rimosse)

Potresti avere una funzione definita dall'utente che ha restituito i PK delle righe corrispondenti, relativamente facile da eseguire un

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

per ottenere il conteggio, quindi

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

per ottenere i dati.

Non so quanto questo si adatti a Row_Number per il successivo paging, ma manterrebbe la logica di query "quot" " contenuto in MyQueryFunction: avrai ancora tutti i JOIN per qualsiasi colonna da recuperare duplciate in Sproc e nella funzione.

Potrebbe non essere d'aiuto con il tuo problema specifico, ma SQL 2005 introduce la funzione Row_Number che è utile per il controllo del paging

Esempio di numero di riga

Molto più semplice delle tabelle temporanee.

Ho trovato questo thread alla ricerca di qualcos'altro e ho pensato di menzionare che è possibile restituire il set di risultati e il conteggio dei record con una query. Hai solo bisogno di un parametro 'out' per portare il valore. Di seguito è una copia / incolla di un esempio Oracle, ma la tecnica è molto simile per SQL Server (non ho accesso a SQL Server atm).

La cosa importante con SQL Server è che potresti dover usare 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;

Conosco una vecchia domanda (che è già stata contrassegnata), ma puoi restituire un recordset (ovvero i risultati) E avere un valore OUTPUT (o output multiplo) che significa che hai solo bisogno di un round trip al database .

Questo è qualcosa che sto pensando ad alta voce (ed è già passato il mio momento di andare a letto ...)

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top