Получение значений для хранимой процедуры постраничного поиска SQL
-
06-07-2019 - |
Вопрос
Я написал хранимую процедуру постраничного поиска с использованием 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, которая удобна для проверки подкачки
Намного проще, чем временные таблицы.
Я нашел этот поток, исследующий что-то еще, и подумал, что стоит упомянуть, что можно вернуть результирующий набор и количество записей одним запросом.Вам просто нужен параметр '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
ХТХ.