본문 바로가기

개인공부/웹

SQL 쿼리 튜닝 팁 [출처 _ 책 국내 정상의 시스템 프로그래머가 알려주는 웹사이트 튜닝]



SQL 쿼리 튜닝 팁

1. SELECT * ... 문장은 피하세요.
쿼리의 결과로 모든 필드의 결과가 필요한 경우가 아니라면 SELECT리스트에 필요한 필드들을 일일이 적어 주어야 합니다. 즉, "SELECT * From Table" 과 같은 쿼리는 "SELECT Field1, Field2 From Table ..."과 같이 필요한 필드를 밝힌 쿼리로 작성하기 바랍니다.

2. 알맞은 인덱스를 구성해서 쿼리가 인덱스를 타게 하세요.
(효율적으로 인덱스를 구성하고 사용한다면 쿼리의 속도를, 그리고 궁극적으로는 DB 서버의 퍼포먼스를 놀라울 정도로 향상시킬 수 있습니다.)

3. 쿼리가 여러 번 DB서버에 들어가지 않게 하세요.
만일 웹 서버가 DB 서버에 데이터를 요청할 때 저장 프로시저를 사용하지 않고 웹 서버에서 작성한 쿼리를 DB서버에 보내는 방식이라면, 되도록 쿼리가 DB서버에 자주 들어가지 않도록 작성하기 바랍니다. 
ex. 루프 내에서 단순한 SELECT쿼리를 계속 부르는 실수입니다. 이러한 경우에는 필요한 데이터를 모두 SELECT해서 가져온 다음에 레코드셋을 가지고 루프 연산을 수행하는 것이 좋습니다. 
ex. UPDATE 쿼리를 사용할 때 종종 실수를 하는 일이 있습니다. 어떤 값을 하나 증가시키기 위해 해당 값을 일단 SELECT 해 와서 그 값을 하나 증가시킨 뒤에 데이터를 업데이트하는 경우가 있습니다.
이런 경우에는 당연히 "UPDATE Table SET Field = Field + 1 WHERE ..."와 같은 쿼리로 해당 값을 SELECT하지 말고 한번의 UPDATE쿼리로 처리하는 것이 좋습니다.
ex. 서브쿼리가 있다는 것을 인식하지 못하는 데서 일어나는 실수도 있습니다.
(즉, SELECT쿼리를 통해서 데이터를 반환 받고 반환 받은 값을 변환한 다음, INSERT쿼리를 통해서 변환한 값을 다른 테이블에 넣는 경우가 이러한 예에 해당합니다.)

4. JOIN쿼리에서 사용 메모리를 줄이는 방법을 생각하세요.
기본적으로 JOIN (여기에서는 Inner Join)을 사용하면 ON 절에 밝힌 조건에 의해서 데이터를 추린 다음 WHERE 절 조건을 적용합니다. 따라서 ON 절 조건에 의해 추려지는 데이터는 메모리에 설정됩니다.
이때 아예 JOIN을 피할 수 있도록 테이블을 구성할 수 있다면 그렇게 하는 것이 가장 좋은 방법이겠지만, 그렇게 할 수 없다면 되도록 JOIN 할 때 설정되는 임시 메모리의 크기가 작게 만들어지도록 두 테이블에서 값은 같지만 메모리는 더 작게 차지하는 필드를 찾아 그것을 ON조건에 사용하는 것이 유리합니다.

5. SELECT가 많다면 NOLOCK 힌트를 줄 수도 있어요. ( NOLOCK이란 DB서버 내부적으로 해당 데이터를 읽고 있음을 표시해 주는 LOCK을 설정하지 않는 것을 의미합니다.)
서비스 내용 구성상 SELECT 쿼리는 자주 일어나는데 INSERT나 UPDATE쿼리는 거의 일어나지 않는 환경이라면 
"SELECT Field1 FROM Table (NOLOCK) ..."과 같이 NOLOCK 힌트를 주면 좋습니다.
참고로 NOLOCK힌트의 단점은 NOLOCK을 쓰게 되면 변화된 데이터 내용을 반영하지 않거나, 데이터가 변경 중이라도 데이터를 읽어 오는 현상이 일어날 수 있기 때문에 사용상의 주의가 요구됩니다. 다이내믹 타입의 레코드셋을 사용하는 것과 같이 변경된 값이 바로 반영되어야 하는 환경이 아니라면 크게 문제 되지는 않을 것이지만요.

6. TOP을 이용해서 필요한 만큼만 부르세요.
"SELECT * ..."가 불필요한 데이터까지 다 반환하는 좋지 못한 예였다면, TOP을 사용하지 않아서 필요도 없는 데이터 행(Row)까지 반환하는 것도 비슷한 맥락에서 퍼포먼스를 저하시키는 예라고 할 수 있습니다. 
예를 들어 서비스의 한 웹 페이지에 게시판 목록을 보여주는 기능, 즉 어떤 자료에 대한 리스트를 10개 보여 주고 다음 페이지로 넘어가면 다음 리스트 10개를 보여 주는 페이지를 작성한다고 합시다. 그러면 처음 웹 페이지를 구성하는 데에 필요한 데이터는 10개인데도 불구하고 모든 데이터 행을 다 SELECT해 온 다음, 웹 스크립트에서 루프를 10번 돌리면서 페이지를 꾸미는 경우를 자주 보았습니다. 이렇게 하면 리스트 페이지를 하나씩 넘어갈 때마다 전체 데이터가 반환되므로 네트워크 부하는 물론이고 웹 서버와 DB 서버의 메모리 부하도 커지게 되므로 결코 좋은 방법이라고 할 수 없습니다. 이런 경우에는 "SELECT TOP n ..."과 같이 TOP을 써서 필요한 수만큼 데이터를 반환하도록 해 줍니다. 

7. 빠른 데이터 개수 반환 팁을 쓰세요.   <- mysql에선 어떻게하지..?
테이블에 저장되어 있는 데이터의 총 개수를 알아내기 위해서 
"SELECT COUNT (PromaryKeyField) ..."      혹은      "SELECT COUNT(*) ..."와 같이 COUNT함수를 사용하는 경우가 있습니다. 이것이 잘못되었다는 말이 아니고 만일 테이블에 있는 데이터 행의 총 개수를 알아내고자 하는 경우라면 
"SELECT rows FROM sysindexes WHERE id = OBJECT_ID('Table이름') AND indid <2" 의 쿼리를 사용하는 편이 속도가 훨씬 빠르다는 것입니다.   (총 개수를 구하고자 할 때 사용하며, 일부 개수를 구할 수는 없습니다.)

8. 쿼리 분석기로 쿼리를 분석하세요.ㅜㄱ내 
쿼리 분석기를 이용하는 방법은 쿼리 자체를 튜닝하는 팁은 아니지만, 쿼리 튜닝과 밀접한 관계에 있기 때문에 여기에 한 항목으로 구성했습니다.


출처 : 국내 정상의 시스템 프로그래머가 알려주는 웹사이트 튜닝. [책]