Получение значений для хранимой процедуры постраничного поиска SQL

StackOverflow https://stackoverflow.com/questions/259039

Вопрос

Я написал хранимую процедуру постраничного поиска с использованием SQL Server 2005.Для этого требуется несколько параметров, а критерии поиска умеренно сложные.

Из-за интерфейсной архитектуры мне нужно иметь возможность возвращать количество результатов, которые будут возвращены без фактически возвращая результаты.Затем интерфейс вызовет хранимую процедуру во второй раз, чтобы получить фактические результаты.

С одной стороны, я могу написать две хранимые процедуры - одну для обработки подсчета, а другую для обработки фактических данных, но тогда мне нужно поддерживать логику поиска по крайней мере в двух разных местах.В качестве альтернативы, я могу написать хранимую процедуру так, чтобы она принимала битовый параметр и на основе этого либо возвращала данные, либо просто количество.Возможно, заполните временную таблицу данными, и если это количество, просто сделайте подсчет из этого, в противном случае сделайте выбор из него.Проблема здесь в том, что процесс подсчета можно было бы оптимизировать, так что, похоже, это сопряжено с большими дополнительными накладными расходами (приходится получать ненужные столбцы и т.д.).Кроме того, использование такого рода логики в хранимой процедуре может привести к неправильным планам запросов при переходе от одного использования к другому.

Объем данных в системе не слишком велик (всего пара миллионов строк даже для таблиц большего размера).Однако одновременных пользователей может быть много.

Что думают люди об этих подходах?Кто-нибудь решал эту проблему раньше способом, о котором я не подумал?

Они НЕ МОЖЕТ считайте результаты одновременно с одного вызова.

Спасибо!

Это было полезно?

Решение

Лично я придерживаюсь подхода с двумя запросами, да, вам приходится поддерживать логику поиска в двух местах, но я обнаружил, что преимущества оптимизации производительности и общая чистота кода в конечном итоге окупаются.

Использование флага, переданного одной процедуре, является потенциальным решением, но я просто нахожу это очень сложным в обслуживании, особенно для сложной логики поиска.

Маршрут использования временных таблиц и т.д., который просто добавляет НАМНОГО больше накладных расходов, чем то, что необходимо.

Итак, почему я остановился на методе two query.Все, что я нахожу в Интернете, также рекомендует этот подход.

Другие советы

Это необычная проблема, и обычно вы хотите подсчитать общее количество одновременно с получением страницы.

Тем не менее, используйте две разные процедуры.Причина в том, что у вас есть два совершенно разных действия, которые лишь внешне похожи друг на друга.

Я уверен, что вы обдумывали это:Если данные изменяются, количество и любая последующая фактическая подкачка страниц могут отличаться (если добавлены / удалены строки)

У вас могла бы быть определенная пользователем функция, которая возвращала PKS совпадающих строк, относительно простая в выполнении

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

чтобы получить подсчет, а затем

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

чтобы получить данные.

Не знаю, насколько хорошо это сочетается с Row_Number для последующей подкачки, но это сохранит фактическую "логику запроса", содержащуюся в MyQueryFunction - у вас все равно будут дублироваться все соединения для любого извлекаемого столбца в Sproc и функции.

Возможно, это не поможет с вашей конкретной проблемой, но SQL 2005 вводит функцию Row_Number, которая удобна для проверки подкачки

Пример Row_number

Намного проще, чем временные таблицы.

Я нашел этот поток, исследующий что-то еще, и подумал, что стоит упомянуть, что можно вернуть результирующий набор и количество записей одним запросом.Вам просто нужен параметр 'out' для переноса значения.Ниже приведен пример копирования / вставки Oracle, но этот метод очень похож для SQL Server (у меня нет доступа к SQL Server atm).

Большая проблема с SQL Server заключается в том, что вам может потребоваться использовать row_number() вместо 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;

Я знаю, что это старый вопрос (который уже был отмечен), но вы можете вернуть набор записей (он же результаты) И получить выходные (или несколько выходных) значений, что означает, что вам нужен только один обратный переход к базе данных.

Это то, о чем я думаю вслух (и мне уже давно пора спать ...)

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

ХТХ.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top