문제

가능한 경우 저장 프로시저에서 커서를 사용하지 않는 것이 일반적으로 허용됩니다(집합 기반 논리 등으로 대체).일부 데이터를 반복해야 하고 읽기 전용 방식으로 수행할 수 있는 경우, 빨리 감기(읽기 전용 앞으로) 커서는 while 루프보다 다소 비효율적입니까?내 조사에 따르면 커서 옵션이 일반적으로 더 빠르고 읽기 및 CPU 시간을 덜 사용하는 것 같습니다.나는 광범위한 테스트를 수행하지 않았지만 이것이 다른 사람들이 찾은 것입니까?이 유형(빨리 감기)의 커서는 내가 알지 못하는 비용이 많이 들 수 있는 추가 오버헤드나 리소스를 전달합니까?

커서를 사용하지 않는 것에 대한 모든 이야기는 실제로 집합 기반 접근 방식을 사용할 수 있는 경우 커서 사용을 피하고 업데이트 가능한 커서를 사용하는 것에 관한 것입니다.

감사해요

도움이 되었습니까?

해결책

SQL Server에서 커서를 피하는 '모범 사례'는 SQL Server 2000 및 이전 버전으로 거슬러 올라갑니다.SQL 2005에서 엔진을 다시 작성하면 특히 빨리 감기 옵션이 도입되면서 커서 문제와 관련된 대부분의 문제가 해결되었습니다.커서는 반드시 집합 기반보다 나쁘지 않으며 Oracle PL/SQL(LOOP)에서 광범위하고 성공적으로 사용됩니다.

당신이 언급하는 '일반적으로 허용되는' ~였다 유효하지만 이제는 오래되고 부정확합니다. 빨리 감기 커서가 광고된 대로 작동하고 수행한다고 가정합니다.SQL2005 이상을 기반으로 몇 가지 테스트와 조사를 수행합니다.

다른 팁

SQL Server 2005에서는 빨리 감기 커서가 일부 최적화되었지만 ~ 아니다 성능 측면에서 집합 기반 쿼리에 가까운 것은 사실입니다.커서 논리를 집합 기반 쿼리로 대체할 수 없는 상황은 거의 없습니다.로컬 변수를 채우기 위해 실행을 계속 중단해야 하기 때문에 커서는 본질적으로 항상 느려집니다.

다음은 이 문제를 조사한 경우 빙산의 일각에 불과한 몇 가지 참고 자료입니다.

http://www.code-magazine.com/Article.aspx?quickid=060113

http://dataeducation.com/re-inventing-the-recursive-cte/

이 답변은 현재까지 제공된 답변을 통합하기를 희망합니다.

1) 가능하다면 쿼리에 집합 기반 논리를 사용했습니다.그냥 사용해 보고 사용해 보세요 SELECT, INSERT, UPDATE 또는 DELETE 적절한 FROM 절 또는 중첩 쿼리 - 거의 항상 더 빠릅니다.

2) 위의 방법이 불가능할 경우 SQL Server 2005+에서는 FAST FORWARD 커서는 효율적이고 성능이 뛰어나므로 while 루프보다 우선적으로 사용해야 합니다.

"FAST FORWARD보다 더 빠른 커서를 원한다면 STATIC 커서를 사용하십시오.FAST FORWARD보다 빠릅니다.아주 빠르지는 않지만 변화를 가져올 수 있습니다."

그렇게 빠르지는 않아요!마이크로소프트에 따르면:"일반적으로 이러한 변환이 발생하면 커서 유형이 '더 비싼' 커서 유형으로 저하되었습니다.일반적으로 (FAST) FORWARD-ONLY 커서가 가장 성능이 뛰어나고 그 다음은 DYNAMIC, KEYSET, 마지막으로 STATIC이 가장 성능이 낮습니다."

에서: http://blogs.msdn.com/b/mssqlisv/archive/2006/06/23/644493.aspx

대부분의 경우 커서를 피할 수 있지만 때로는 필요한 경우도 있습니다.

FAST_FORWARD는 DYNAMIC이라는 점을 명심하세요.FORWARD_ONLY STATIC 커서와 함께 사용할 수 있습니다.

무슨 일이 일어나는지 할로윈 문제에 사용해 보세요!!!

IF OBJECT_ID('Funcionarios') IS NOT NULL
DROP TABLE Funcionarios
GO

CREATE TABLE Funcionarios(ID          Int IDENTITY(1,1) PRIMARY KEY,
                          ContactName Char(7000),
                          Salario     Numeric(18,2));
GO

INSERT INTO Funcionarios(ContactName, Salario) VALUES('Fabiano', 1900)
INSERT INTO Funcionarios(ContactName, Salario) VALUES('Luciano',2050)
INSERT INTO Funcionarios(ContactName, Salario) VALUES('Gilberto', 2070)
INSERT INTO Funcionarios(ContactName, Salario) VALUES('Ivan', 2090)
GO

CREATE NONCLUSTERED INDEX ix_Salario ON Funcionarios(Salario)
GO

-- Halloween problem, will update all rows until then reach 3000 !!!
UPDATE Funcionarios SET Salario = Salario * 1.1
  FROM Funcionarios WITH(index=ix_Salario)
 WHERE Salario < 3000
GO

-- Simulate here with all different CURSOR declarations
-- DYNAMIC update the rows until all of then reach 3000
-- FAST_FORWARD update the rows until all of then reach 3000
-- STATIC update the rows only one time. 

BEGIN TRAN
DECLARE @ID INT
DECLARE TMP_Cursor CURSOR DYNAMIC 
--DECLARE TMP_Cursor CURSOR FAST_FORWARD
--DECLARE TMP_Cursor CURSOR STATIC READ_ONLY FORWARD_ONLY
    FOR SELECT ID 
          FROM Funcionarios WITH(index=ix_Salario)
         WHERE Salario < 3000

OPEN TMP_Cursor

FETCH NEXT FROM TMP_Cursor INTO @ID

WHILE @@FETCH_STATUS = 0
BEGIN
  SELECT * FROM Funcionarios WITH(index=ix_Salario)

  UPDATE Funcionarios SET Salario = Salario * 1.1 
   WHERE ID = @ID

  FETCH NEXT FROM TMP_Cursor INTO @ID
END

CLOSE TMP_Cursor
DEALLOCATE TMP_Cursor

SELECT * FROM Funcionarios

ROLLBACK TRAN
GO

사람들은 일반적으로 간단한 while 루프보다 작성하기가 더 어렵기 때문에 커서를 피합니다. 그러나 while 루프는 임시 또는 기타 테이블에서 지속적으로 데이터를 선택하기 때문에 비용이 많이 들 수 있습니다.

읽기 전용 빨리 감기 커서를 사용하면 데이터가 메모리에 보관되며 루핑용으로 특별히 설계되었습니다.

이 기사 평균 커서가 while 루프보다 50배 빠르게 실행된다는 점을 강조합니다.

커서 사용에 대한 몇 가지 대안:

루프 임시 타판형 파생 테이블과 관련된 서브 쿼리 사례 문장 여러 심문이 종종 커서 작업을 수행 할 수 있습니다.

커서를 사용해야 한다고 확신하는 경우에는 처리할 레코드 수를 최대한 줄여야 합니다.이를 수행하는 한 가지 방법은 원본 테이블이 아닌 임시 테이블의 레코드를 사용할 커서가 아닌 임시 테이블로 먼저 처리할 레코드를 가져오는 것입니다.이 경로를 사용하면 원본 테이블에 비해 임시 테이블의 레코드 수가 크게 줄어든 것으로 가정됩니다.레코드 수가 적을수록 커서가 더 빨리 완료됩니다.

성능에 영향을 미치는 일부 커서 속성은 다음과 같습니다.

FORWARD_ONLY:FETCH NEXT를 사용하여 첫 번째 행부터 끝까지 커서만 전달을 지원합니다.KEYSET 또는 STATIC으로 설정되지 않은 경우 각 가져오기가 호출될 때 SELECT 절이 다시 평가됩니다.

공전:생성된 데이터의 임시 복사본을 생성하고 커서에서 사용합니다.이렇게 하면 커서가 호출될 때마다 다시 계산되는 것을 방지하여 성능이 향상됩니다.이는 커서 유형 수정을 허용하지 않으며, 페치 호출 시 테이블 변경 사항이 반영되지 않습니다.

키셋:커서가 있는 행은 tempdb 아래의 테이블에 배치되고 키가 아닌 열의 변경 사항은 가져오기가 호출될 때 반영됩니다.그러나 테이블에 추가된 새로운 레코드는 반영되지 않습니다.키 세트 커서를 사용하면 SELECT 문이 다시 평가되지 않습니다.

동적:테이블에 대한 모든 변경 사항은 커서에 반영됩니다.각 페치가 호출될 때 커서가 다시 평가됩니다.많은 리소스를 사용하고 성능에 부정적인 영향을 미칩니다.

빨리 감기:커서는 FORWARD_ONLY와 같은 단방향이지만 커서를 읽기 전용으로 지정합니다.FORWARD_ONLY는 성능을 향상시키며 가져올 때마다 커서가 재평가되지 않습니다.프로그래밍에 적합하다면 최고의 성능을 제공합니다.

낙관적인:이 옵션은 커서의 행을 업데이트하는 데 사용할 수 있습니다.행을 가져와서 업데이트하고 가져오기와 업데이트 작업 사이에 다른 행을 업데이트하면 커서 업데이트 작업이 실패합니다.행 업데이트를 수행할 수 있는 OPTIMISTIC 커서를 사용하는 경우 다른 프로세스에서 업데이트하면 안 됩니다.

메모:커서가 지정되지 않은 경우 기본값은 FORWARD_ONLY입니다.

Mile의 원래 질문에 답하려면...

빨리 감기, 읽기 전용, 정적 커서("소방 호스 커서"라고도 함)는 일반적으로 동등한 임시 테이블 및 While 루프보다 빠르거나 빠릅니다. 왜냐하면 이러한 커서는 임시 테이블 및 While 루프에 지나지 않기 때문입니다. 뒤에서 약간 최적화되었습니다.

Eric Z에 추가하려면Beard는 이 스레드에 게시했으며 다음 질문에 대한 추가 답변을 제공합니다.

"세트 기반 접근 방식을 사용할 수있을 때 커서의 사용을 피하고 업데이트 가능한 커서 등을 사용하는 것에 대한 커서를 사용하지 않는 것에 대한 모든 이야기입니다."

예.거의 예외를 제외하면 대부분의 커서와 동일한 작업을 수행하기 위해 적절한 집합 기반 코드를 작성하는 데 시간과 코드가 덜 소요되며 훨씬 적은 리소스를 사용하는 추가 이점이 있으며 일반적으로 커서나 While 루프보다 훨씬 빠르게 실행됩니다.일반적으로 특정 관리 작업을 제외하고는 적절하게 작성된 집합 기반 코드를 선호하므로 이러한 작업은 실제로 피해야 합니다.물론 모든 "규칙"에는 예외가 있지만 커서, While 루프 및 기타 형태의 RBAR의 경우 대부분의 사람들은 손가락을 모두 사용하지 않고도 한 손으로 예외를 셀 수 있습니다.;-)

"Hidden RBAR"라는 개념도 있습니다.이는 집합 기반으로 보이지만 실제로는 그렇지 않은 코드입니다.이러한 유형의 "세트 기반" 코드는 특정 사람들이 RBAR 방법을 채택하고 "괜찮다"고 말하는 이유입니다.예를 들어, 누계를 구축하기 위해 불평등이 있는 집계된(SUM) 상관 하위 쿼리를 사용하여 누계 문제를 해결하는 것은 실제로 내 책에서 설정 기반이 아닙니다.대신, 계산된 각 행에 대해 N*(N+1)/2의 비율로 다른 많은 행을 반복적으로 "접촉"해야 하기 때문에 이는 스테로이드의 RBAR입니다.이는 "삼각 조인"으로 알려져 있으며 전체 데카르트 조인(교차 조인 또는 "정사각형 조인")의 절반 정도입니다.

MS는 SQL Server 2005 이후로 커서 작동 방식을 일부 개선했지만 "빠른 커서"라는 용어는 적절하게 작성된 집합 기반 코드와 비교하면 여전히 모순적입니다.이는 Oracle에서도 마찬가지입니다.나는 과거에 짧은 3년 동안 Oracle에서 일했지만 내 임무는 기존 코드의 성능을 개선하는 것이었습니다.커서를 세트 기반 코드로 변환했을 때 실제로 상당한 개선이 이루어졌습니다.이전에는 실행하는 데 4~8시간이 걸리던 많은 작업이 몇 분, 때로는 몇 초로 단축되었습니다.

FAST FORWARD보다 더 빠른 커서를 원한다면 STATIC 커서를 사용하십시오.FAST FORWARD보다 빠릅니다.매우 빠르지는 않지만 차이를 만들 수 있습니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top