PAGED SQL 검색 저장 프로 시저에 대한 계산
-
06-07-2019 - |
문제
SQL Server 2005를 사용하여 PAGED 검색 저장 프로 시저를 작성했습니다. 여러 매개 변수가 필요하며 검색 기준은 적당히 복잡합니다.
프론트 엔드 아키텍처로 인해 돌아올 결과 수를 반환 할 수 있어야합니다. 없이 실제로 결과를 반환합니다. 그런 다음 프론트 엔드는 저장 절차를 두 번째로 호출하여 실제 결과를 얻습니다.
한편으로는 두 개의 저장된 절차를 작성할 수 있으며, 하나는 카운트를 처리하고 실제 데이터를 처리하기 위해 하나는 검색 로직을 최소한 두 개의 다른 장소로 유지해야합니다. 또는 저장된 절차를 작성하여 약간의 매개 변수를 가져 와서 데이터를 반환하거나 카운트만으로도 작성할 수 있습니다. 데이터로 임시 테이블을 채우고 카운트가 있다면 그로부터 카운트 만하면 선택을 수행 할 수 있습니다. 여기서 문제는 카운트 프로세스를 최적화 할 수 있으므로 더 많은 오버 헤드가 될 수 있다는 것입니다 (불필요한 열 등을 얻어야합니다). 또한 저장된 프로 시저에서 이러한 종류의 논리를 사용하면 두 용도 사이를왔다 갔다 할 때 쿼리 계획이 잘못 될 수 있습니다.
시스템의 데이터 양은 너무 높지 않습니다 (더 큰 테이블에 대해서도 2 백만 행만). 동시 사용자가 많이있을 수 있습니다.
이 접근법에 대한 사람들의 생각은 무엇입니까? 내가 생각하지 않은 방식 으로이 문제를 해결 한 사람이 있습니까?
그들 할 수 없습니다 결과를 가져 와서 동시에 한 번의 통화에서 계산하십시오.
감사!
해결책
개인적으로 두 쿼리 접근 방식을 사용합니다. 예, 검색 논리를 두 곳에서 유지해야하지만 성능 최적화 이점과 코드의 전반적인 청소가 결국 지불된다는 것을 알았습니다.
단일 절차로 전달 된 깃발을 사용하는 것은 잠재적 인 해결책이지만, 특히 복잡한 검색 논리를 위해 유지하기가 매우 어렵다는 것을 알게됩니다.
임시 테이블 등을 사용하는 경로는 필요한 것보다 더 많은 오버 헤드를 추가합니다.
따라서 왜 두 쿼리 방법으로 착륙 한 이유. 온라인에서 찾은 모든 것은이 접근법도 권장합니다.
다른 팁
이것은 정상적인 문제가 아니며 일반적으로 페이지를 얻는 동시에 총 카운트를 원합니다.
즉, 두 가지 절차를 사용하십시오. 그 이유는 당신이 서로 표면적으로 만 닮은 두 가지 매우 다른 행동이 있기 때문입니다.
나는 당신이 이것을 고려했다고 확신합니다 : 데이터가 카운트를 변경하고 있으며 그 이후의 실제 페이징이 다를 수 있다면 (행이 추가 / 제거 된 경우)
일치하는 행의 PK를 반환하는 사용자 정의 함수를 가질 수 있으며, 비교적 쉽게
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에 포함 된 실제 "쿼리 로직"을 유지할 것입니다. 스프로와 스프로에서 검색 할 열에 대한 모든 조인이 여전히 결합 될 것입니다. 함수.
이 스레드가 다른 것을 연구하는 것을 발견했으며 결과 세트와 레코드 수를 하나의 쿼리로 반환 할 수 있다고 언급했습니다. 값을 전달하려면 '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;
나는 이것 (이미 표시된)을 알고 있지만 레코드 세트 (일명 결과)를 반환하고 출력 (또는 다중 출력) 값을 가질 수 있습니다. 즉, 데이터베이스로의 왕복이 하나만 필요하다는 것을 의미합니다.
이것은 내가 큰 소리로 생각하고있는 것입니다 (그리고 내 침대 시간을 지나서 waaay입니다 ...)
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.