Pregunta

He escrito un procedimiento almacenado de búsqueda paginada usando SQL Server 2005. Toma una serie de parámetros y el criterio de búsqueda es moderadamente complejo.

Debido a la arquitectura front-end, necesito poder devolver el número de resultados que se obtendrían sin realmente devolver los resultados. El front end llamaría al procedimiento almacenado por segunda vez para obtener los resultados reales.

Por un lado, puedo escribir dos procedimientos almacenados: uno para manejar el recuento y otro para manejar los datos reales, pero luego necesito mantener la lógica de búsqueda en al menos dos lugares diferentes. Alternativamente, puedo escribir el procedimiento almacenado para que tome un parámetro de bit y, en función de eso, devuelvo datos o solo un recuento. Tal vez llene una tabla temporal con los datos y si es un recuento solo haga un recuento a partir de eso, de lo contrario, haga una selección. El problema aquí es que el proceso de conteo podría optimizarse, por lo que parece una sobrecarga adicional (tiene que obtener columnas innecesarias, etc.). Además, el uso de este tipo de lógica en un procedimiento almacenado podría generar malos planes de consulta a medida que avanza y retrocede entre los dos usos.

La cantidad de datos en el sistema no es demasiado alta (solo un par de millones de filas incluso para las tablas más grandes). Sin embargo, puede haber muchos usuarios concurrentes.

¿Qué piensa la gente sobre estos enfoques? ¿Alguien ha resuelto este problema antes de una manera que no había pensado?

Ellos NO PUEDEN tomar los resultados y contar al mismo tiempo desde una sola llamada.

¡Gracias!

¿Fue útil?

Solución

Personalmente, sigo con el enfoque de dos consultas, sí, debe mantener la lógica de búsqueda en dos lugares, pero descubrí que el beneficio de optimización del rendimiento y la limpieza general del código al final son rentables.

El uso de un indicador pasado a un solo procedimiento es una solución potencial, pero me resulta muy difícil de mantener, especialmente para la lógica de búsqueda compleja.

La ruta de uso de tablas temporales, etc., que solo agrega MUCHO más sobrecarga de la que se necesita.

Por lo tanto, por qué he aterrizado con los dos métodos de consulta. Todo lo que encuentro en línea recomienda este enfoque también.

Otros consejos

Este no es un problema normal y, por lo general, desea contar los recuentos totales al mismo tiempo que obtiene una página.

Dicho esto, use dos procedimientos diferentes. La razón es que tienes dos acciones muy diferentes que solo se parecen superficialmente.

Estoy seguro de que ha considerado esto: si los datos están cambiando el COUNT y cualquier paginación real posterior puede ser diferente (si se agregan / eliminan filas)

Podría tener una función definida por el usuario que devolviera las PK de las filas coincidentes, relativamente fácil de hacer una

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

para obtener el recuento y luego

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

para obtener los datos.

No sé qué tan bien se sienta esto con Row_Number para la paginación posterior, pero mantendría la " lógica de consulta " real contenido en MyQueryFunction: aún tendrá todas las UNIONES para que cualquier columna se recupere duplicada en Sproc y la Función.

Puede que no ayude con su problema específico, pero SQL 2005 presenta la función Row_Number que es útil para la verificación de paginación

Ejemplo de Row_number

Mucho más fácil que las tablas temporales.

Encontré este hilo investigando algo más, y pensé en mencionar que es posible devolver el conjunto de resultados y el recuento de registros con una consulta. Solo necesita un parámetro 'out' para llevar el valor. A continuación se muestra una copia / pegado de un ejemplo de Oracle, pero la técnica es muy similar para SQL Server (no tengo acceso al cajero automático de SQL Server).

La gran cosa con SQL Server es que puede que necesite usar 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;

Sé que esta es una pregunta anterior (que ya se ha marcado), pero puede devolver un conjunto de registros (también conocido como los resultados) Y tener valores de SALIDA (o salida múltiple), lo que significa que solo necesita un viaje de ida y vuelta a la base de datos .

Esto es algo que estoy pensando en voz alta (y ya pasó mi hora de dormir ...)

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top