2012-02-16 2 views
7

나는 사람들이 말하는 커서를 사용해서는 안됩니다 반응했다 여기 Using cursor in OLTP databases (SQL server)장점과 (SQL 서버)에 커서를 사용하는 단점

질문을 물었다.

커서가 사용하기에 매우 강력한 도구라고 느낍니다. Microsoft에서 나쁜 개발자가 커서를 지원하지 않는다고 생각합니다. 행의 열 값이 값에 종속되어있는 테이블 이전 행의 동일한 열의 한 번 백 엔드 프로세스 인 경우 커서를 사용하는 것이 허용 가능한 선택이라고 생각하지 않습니까?

내 머리 꼭대기에서 나는 커서 사용에 부끄러움을 느끼지 않는 몇 가지 시나리오를 생각할 수 있습니다. 너희들이 다르게 느껴지면 나에게 알려줘.

1> 몇 분 안에 실행을 완료하는 잘못된 데이터를 정리하는 한 번의 백엔드 프로세스입니다. 2> 장기간에 한 번 실행되는 배치 프로세스 (일년에 한 번). 위의 시나리오에서 다른 프로세스에 눈에 띄는 부담이 없으면 커서를 피하기 위해 여분의 시간을 코드를 작성하는 데 무리가 없습니까? 다른 말로하면 어떤 경우에는 개발자의 시간이 다른 어떤 것에도 거의 영향을 미치지 않는 프로세스의 성능보다 더 중요합니다.

제 의견으로는 커서를 사용하지 말아야 할 몇 가지 시나리오가 있습니다. 1> 매우 자주 호출 될 수있는 웹 사이트에서 호출 된 저장 프로 시저입니다. 2> 하루에 여러 번 실행되고 많은 리소스를 소비하는 SQL 작업입니다.

필자는 당면 과제를 분석하고 실제로 대안을 비교하지 않고 "커서를 사용해서는 안됩니다"와 같은 일반 성명을 작성하는 것이 매우 피상적이라고 생각합니다.

귀하의 의견을 알려주십시오.

+1

Sql Server 2012는 집합 기반 방식으로 이전 행의 값을 가져 오는 경우를 지원합니다. – automatic

+1

"웹 사이트에서 호출 된 저장 프로 시저"는 너무 모호합니다. 커서가 문제를 해결하기위한 가장 합리적인 선택이고 웹 페이지에서 프로 시저를 호출해야하는 경우 ... –

답변

11

커서가 실제로 세트 기반의 동등 물보다 성능이 좋은 시나리오가 몇 가지 있습니다. 누적 합계는 항상 염두에 두어야 할 것입니다. Itzik의 말을 찾아보십시오 (이 상황에서 커서를 돈으로 사용할 수있는 새로운 창 함수를 추가하는 SQL Server 2012와 관련된 것은 무시하십시오). 사람들이 커서에있는 큰 문제의

하나는 기본 구문이 비효율적 기본 옵션의 모든 종류의 글로벌 커서이기 때문에 이것은 부분적 등, 그들은 임시 저장소를 사용, 천천히 수행 할 것입니다. 다음 번에 UPDATE...WHERE CURRENT OF과 같은 작업을 수행 할 필요가없는 커서를 사용하여 (나는 전체 경력을 피할 수 있었음) 다음 두 가지 구문 옵션을 비교하여 적절하게 흔들어보십시오.

첫 번째 버전은이 데이터베이스를 건너 뛸 수 있습니다 문서화되지 않은 저장 프로 시저 sp_MSforeachdb의 버그를 나타냅니다 사실
DECLARE c CURSOR 
    FOR <SELECT QUERY>; 

DECLARE c CURSOR 
    LOCAL STATIC READ_ONLY FORWARD_ONLY 
    FOR <SELECT QUERY>; 

경우 실행 중에 모든 데이터베이스의 상태가 변경. 이후에 위의 구문을 사용하여 버그를 수정 한 저장 프로 시저 (herehere 참조)의 자체 버전을 작성하고 어떤 데이터베이스를 선택 할지를 제어하는 ​​여러 매개 변수를 추가했습니다.

명 많은는 DECLARE CURSOR 말을하지 않기 때문에 방법론이 커서 아니라고 생각합니다. while 루프가 커서 (which I hope I've dispelled here)보다 빠르거나 그룹 연결을 수행하기 위해 FOR XML PATH을 사용하면 숨겨진 커서 작업을 수행하지 않는다고 주장하는 사람들이 있습니다. 많은 경우에 계획을 보는 것은 진실을 보여줄 것입니다. 집합 기보다 적절한 곳에 케이스 커서 많이

사용된다. 그러나 세트 기반의 등가물이 쓰는 것이 훨씬 더 복잡하고 옵티마이 저가 가능하거나 불가능한 계획을 생성 할 수있는 유용한 유스 케이스가 많이 있습니다 (예 : 테이블을 반복하여 통계를 업데이트하는 유지 보수 작업, 결과의 각 값에 대한 저장 프로 시저 호출 등). 최적화 프로그램이 처리하기에는 계획이 너무 괴롭히는 많은 대규모 다중 테이블 쿼리에 대해서도 마찬가지입니다. 이러한 경우 중간 결과 중 일부를 먼저 임시 구조로 덤프하는 것이 좋습니다. 동일한 집합 기반 커서에 해당하는 항목 (예 : 누적 합계)도 마찬가지입니다. 나는 또한 사람들이 거의 항상 while 루프/커서를 사용하도록 본능적으로 생각하고 clever set-based alternatives that are much better이있는 다른 방법에 대해 작성했습니다.

UPDATE가

2013년 7월 25일 그냥 당신이이 그들을 사용해야합니까 경우 사용하고 사용해야 옵션 내가 커서에 대해 쓴 몇 가지 추가 블로그 게시물 추가하고 싶었 설정을 기반 대신 루프의 쿼리 세트를 생성 :

Best Approaches for Running Totals - Updated for SQL Server 2012

What impact can different cursor options have?

루프없는 설정 또는 시퀀스 생성 :를[Part 2][Part 3]

6

SQL Server에서 커서와 관련된 문제는 내부적으로 커서 기반 인 Oracle과 같은 다른 DBMS와 달리 엔진이 내부적으로 설정된다는 것입니다. 즉, SQL Server에서 커서를 만들 때 임시 저장소를 만들어야하고 집합 기반 결과 집합을 임시 커서 저장소에 복사해야합니다. 왜 이것이 배트당 값 비싼 지 알 수 있습니다. 커서 자체에서 수행하는 행 단위 처리는 말할 것도 없습니다. 결론은 세트 기반 처리가 더 효율적이며 종종 커서 기반 조작이 CTE 또는 임시 테이블을 사용하여 더 잘 수행 될 수 있다는 것입니다.

즉, 일회용 작업에서 말했던 것처럼 커서가 아마도 허용되는 경우가 있습니다. 내가 생각할 수있는 가장 보편적 인 사용은 다양한 유지 관리 작업을 실행하는 서버의 모든 데이터베이스를 반복 할 수있는 유지 관리 계획에 있습니다. 사용량을 제한하고 RBAR (row-by-agonizing-row) 프로세싱을 중심으로 전체 애플리케이션을 설계하지 않는 한 괜찮습니다.

3

일반적으로 커서는 나쁜 것입니다. 그러나 어떤 경우에는 커서를 사용하는 것이 더 실용적이며 일부에서는 커서를 사용하는 것이 더 빠릅니다. 좋은 예는 몇 가지 기준에 따라 전자 메일을 보내는 연락처 테이블을 통한 커서입니다. DBMS로부터 전자 메일을 보내는 것이 좋은 생각 인 경우 질문을 열지 말라. 당장 문제가 있다고 가정하자.) set-based를 작성할 방법이 없습니다. 당신은 동적 SQL을 생성하기 위해 set 기반의 해결책을 제시하기 위해 몇 가지 속임수를 사용할 수 있지만, 실제 세트 기반 솔루션은 존재하지 않습니다.

그러나 셀프 조인을 사용하면 이전 행을 포함하는 계산을 수행 할 수 있습니다. 대개 커서보다 빠릅니다.

모든 경우에 더 빠른 솔루션을 개발하는 데 필요한 노력의 균형을 유지해야합니다. 아무도 신경 쓰지 않는다면, 1 분 또는 1 시간 안에 실행을 처리하면 작업을 가장 빠르게 처리 할 수 ​​있습니다. [orders] 테이블처럼 시간이 지남에 따라 늘어나는 데이터 세트를 반복하는 경우 가능한 경우 커서에서 멀리 떨어져보십시오. 확실하지 않은 경우 커서 기반을 몇 가지 크게 다른 데이터 크기에서 세트 기반 솔루션과 비교하는 성능 테스트를 수행하십시오.

+1

+1 이전 행 계산이 꽤 복잡해 질 수 있지만, 나는 당신이 말한 것에 동의합니다. 예를 들어 총계 실행 (지금은 시험판 기능 제외)과 같은 대부분의 세트 기반 솔루션으로 작성하십시오. –

0

동적 SQL 피벗과 같은 작업에는 필요하지만 가능할 때마다 사용하지 않는 것이 좋습니다.

0

성능이 좋지 않아 커서를 항상 싫어했습니다. 그러나 필자는 다른 유형의 커서를 완전히 이해하지 못했고 어떤 경우에는 커서가 실행 가능한 솔루션이라는 것을 알았습니다.

한 번에 한 행을 처리해야만 해결할 수있는 비즈니스 문제가있는 경우 커서가 적합합니다.

커서로 성능을 향상 시키려면 사용중인 커서 유형을 변경하십시오. 내가 모르는 뭔가가 있다면, 당신이 선언하고있는 커서의 타입을 지정하지 않으면 기본적으로 Dynamic Optimistic 타입을 얻습니다. 이것은 동적 인 낙관적 인 타입입니다. 이것은 후드에서 많은 일을하기 때문에 성능이 가장 느린 타입입니다 . 그러나 커서를 다른 유형 (정적 커서)으로 선언하면 성능이 매우 좋습니다.

는 풀러 설명은이 문서를 참조하십시오

The Truth About Cursors: Part III

The Truth About Cursors: Part I

The Truth About Cursors: Part II

내가 커서에 대한 가장 큰 사기꾼이 성능이라고 생각하지만,하지 않는에서 작업을 레이아웃 아마도 세트 기반 접근법은 아마도 2 위를 차지할 것입니다. 세 번째는 일반적으로 도움이되는 의견이 많지 않으므로 작업의 가독성 및 레이아웃입니다.

SQL Server는 집합 기반 방식을 실행하도록 최적화되어 있습니다. 예를 들어 테이블에 대한 조인과 같은 결과 데이터 집합을 반환하는 쿼리를 작성하지만 SQL Server 실행 엔진은 병합 조인, 중첩 루프 조인 또는 해시 조인을 사용할 조인을 결정합니다. SQL Server는 참여 열, 데이터 볼륨, 인덱싱 구조 및 참여 열의 값 집합을 기반으로 최상의 결합 알고리즘을 결정합니다. 따라서 집합 기반 접근 방식을 사용하는 것이 절차 적 커서 접근 방식보다 성능면에서 가장 좋은 접근 방식입니다.

관련 문제