안녕하세요.
100만건의 데이터를 하나씩 가져와 1500건의 자료와 하나씩 비교하며 걸러내는..
중첩된 WHILE문으로 데이터 비교 후 필요한 레코드의 SEQ(고유번호)를 구해서
별도의 테이블에 등록해 주는 프로시저를 만들었습니다.
100만건 정도의 데이터를 분류하기 위해 만든 것인데요
처음엔 커서의 중첩 사용으로 WHILE문을 돌리는 것으로 처리했습니다.
그런데 속도가 너무 느린 것이었습니다.
인터넷을 찾아보니 커서는 속도의 문제로 권장하지 않으며 테이블 변수를 만들어 해당 데이터를 넣어준 뒤
WHILE문으로 레코드를 하나씩 가져와 처리하라는 내용을 보고 테이블 변수로 바꾸었습니다.
그런데 테이블 변수를 사용해서 돌려도 속도가 크게 개선되는 것 같진 않았습니다.
대충 12시간 넘게 걸리던 작업이 6~7시간 정도로 줄긴 했으나 ...
100만건 데이터를 WHILE문으로 하나씩 가져와서 약 1500개 정도 되는 데이터를 또 다시 WHILE문으로 비교하면서
데이터를 걸러내는 작업 치고는 너무 오랜 시간이 걸리는 것 같다는 생각 이었습니다.
그래서 인터넷을 다시 찾아 봤습니다.
커서에서 선언부에 커서의 옵션으로 FAST_READONLY 또는 STATIC 등의 옵션을 주면
DEFAULT값인 Dynamic보다 빠르다는 내용을 보고
처음엔 FAST_READONLY 적용을 하였으나 커서가 이미 선언 되었다는 에러 메시지가 나와서
STATIC으로 변경했더니 빠르게 수행 되더군요..
작업 시간이 약 1시간 정도로 매우 빨라 졌습니다.
인터넷에 뒤져보면 커서 사용을 자제하고 테이블 변수를 사용하거나 차선책으로 임시 테이블을 쓰라는 내용이 있던데
지금 이렇게 작업을 해놓고 보니 커서에서 옵션만 선언부에 잘 적용 시키면 엄청 빠른 결과를 가져올 수 있었습니다.
제가 테이블 변수를 잘못 사용한 것일까요? 아니면 커서를 사용하는 것이 맞는 것일까요?
왜 사람들은 커서의 사용이 퍼포먼스에 좋지 못하니 사용하지 말라고 할까요?
몇마디 조언 부탁드립니다.
P.S.
제가 만든 프로시저의 내용이나 예상실행계획을 보시고 싶다면 올려드릴 수 있습니다.
Comment 7
-
초짜해커
2013.09.27 08:29
-
Larry
2013.09.27 10:08
대략 이 작업으로 1달 정도 공부삼아 했습니다.
제 머리로는 루프 돌려서 걸러내는 방법 말고는 지역명을 비교할 방법을 모르겠네요 ㅎㅎ..
지역명칭이 1500여개에 달하는데 이걸 전부 하나씩 비교해서 해당 하는지 아닌지를 판단해야 하는 프로세스인데
좀 더 공부하면서 새로운 방법을 찾아보도록 해야겠습니다 ^^
-
쓸만한게없네(윤선식)
2013.09.27 09:28
커서를 사용하는 것이 무조건 나쁘지는 않습니다.
다만, 경우를 고려하지 않고 사용하는 커서는 성능저하를 가져올 수 있습니다.(결과만 나오면 끝? ... 이라면)
http://technet.microsoft.com/ko-kr/library/ms130840(v=sql.105).aspx
---
커서 기능을 지원하면 기본 결과 집합과 비교해서 성능이 저하될 수 있습니다. 소비자가 커서 기능을 사용하여 더 작은 행 집합을 검색할 수 있는 경우 이러한 성능 저하를 상쇄할 수 있습니다.
---
http://www.microsoft.com/korea/technet/sql/tuning_guide_developer01.mspx
---
수칙4.커서 및 임시 테이블의 내용을 최대한 자제하는가?
결론부터 말씀 드리자면 커서보다는 임시테이블이 임시테이블보다는 테이블 변수를 사용하는 것이 성능에 보탬이 됩니다. 단 SQL2000에서만 테이블 변수가 가능합니다.
커서는 내부적으로 임시 테이블을 사용하기 때문에 임시테이블을 쓴다고 부하가 더 발생하진 않습니다. 오히려 커서의 부가적 기능 때문에 서버 자원을 더 낭비하게 됩니다. (커서로 할 수 있는 건 임시테이블이나 테이블 변수로도 모두 처리가 가능합니다.)
---
이상입니다.
-
Larry
2013.09.27 10:11
음 참고할만한 자료를 주셨군요~ 감사합니다.
말씀하신 수칙대로 테이블변수 > 임시테이블 > 커서 순으로 퍼포먼스를 이야기하는 글들을 몇 개 보았는데요..
지금 저의 경우는 그럼 잘못된 테이블변수 사용으로 커서보다 느린 결과를 얻었다고 할 수도 있겠네요.. 좀 더 공부하며 문제를 찾아봐야겠네요~
-
쓸만한게없네(윤선식)
2013.09.27 10:39
현재 로직을 개선해 보는 것 또한 문제해결에 도움이 될 수 있습니다.
1500여군데를 일일이 비교하신다고 하였는데, 이 ROWS를 줄인다든가,
비교할 테이블 조인 시 인덱스를 아름답게 사용하게 해서 전체 READS 수를 줄인다든가 하는 여러 가지 방법들이 있을 듯 하네요.
짧은 소견이었습니다.
-
Larry
2013.10.01 09:07
답변 감사합니다.
1500여개의 비교 레코드는 더 이상 줄일 수 없어서요~
말씀하신대로 비교할 테이블에 INDEX를 넣어주었습니다. 아무래도 인덱스가 있으니 속도는 좀 더 나아지는 느낌이네요.
-
건우아빠
2013.10.01 09:35
내용에 따라서는 Cross apply (outer apply)로 커서의 일부 기능도 수행가능 합니다.
커서를 쓰지 않고 조인으로도 가능 한 경우가 의외로 있습니다.
커서를 사용하지 않는 방법을 연구해보세요.
커서 없이는 절대로 안된다고 프로그래머가 포기한 프로시져를 UPDATE문 만으로 바꾼적도 있고
분명 커서 없이 가능할겁니다.
테이블 변수든 커서든 루프를 돌리는 방법은 제일 느린 방법일겁니다. (물론 제일 쉬운 방법이기도 합니다만...)