좋아하는 성능 조정 요령 [닫힘]


126

성능 조정이 필요한 쿼리 또는 저장 프로 시저가있는 경우 가장 먼저 시도 할 사항은 무엇입니까?


다음은 SQL Server 쿼리 최적화 요령입니다
SQLMenace

나는 이것이 건설적이지 않고 Google에서 검색 할 수 있다는 데 동의하지만 왜 118 uv가 있습니까?! :)
FLICKER

답변:


114

다음은 최적화에 대해 묻는 사람에게 항상 유용한 것들을 보여줍니다.
우리는 주로 Sybase를 사용하지만 대부분의 조언은 전반적으로 적용됩니다.

예를 들어 SQL Server에는 다양한 성능 모니터링 / 튜닝 비트가 제공되지만 이와 같은 것이 없으면 (아마도 가능할 경우) 다음을 고려할 것입니다 ...

내가 본 문제의 99 %는 너무 많은 테이블을 조인 에 넣음으로써 발생합니다 . 이에 대한 수정은 일부 테이블과 함께 조인의 절반을 수행하고 결과를 임시 테이블에 캐시하는 것입니다. 그런 다음 해당 임시 테이블에서 나머지 쿼리 조인을 수행하십시오.

쿼리 최적화 점검 목록

  • 기본 테이블에서 UPDATE STATISTICS를 실행하십시오.
    • 많은 시스템이이를 예약 된 주간 작업으로 실행합니다
  • 기본 테이블에서 레코드 삭제 (삭제 된 레코드를 아카이브 할 수 있음)
    • 하루에 한 번 또는 일주일에 한 번 자동으로 수행하십시오.
  • 인덱스 재 구축
  • 테이블 재 구축 (bcp 데이터 출력 / 입력)
  • 데이터베이스 덤프 / 다시로드 (과감하지만 손상을 해결할 수 있음)
  • 새롭고 더 적절한 색인 작성
  • DBCC를 실행하여 데이터베이스에 손상이 있는지 확인하십시오.
  • 자물쇠 / 교착 상태
    • 데이터베이스에서 실행중인 다른 프로세스가 없는지 확인
      • 특히 DBCC
    • 행 또는 페이지 수준 잠금을 사용하고 있습니까?
    • 쿼리를 시작하기 전에 테이블을 독점적으로 잠그십시오.
    • 모든 프로세스가 동일한 순서로 테이블에 액세스하고 있는지 확인
  • 지수가 적절하게 사용되고 있습니까?
    • 두 표현식이 정확히 동일한 데이터 유형 인 경우 조인은 인덱스 만 사용합니다.
    • 인덱스의 첫 번째 필드가 쿼리에서 일치하는 경우에만 인덱스가 사용됩니다.
    • 적절한 곳에 군집 지수가 사용됩니까?
      • 범위 데이터
      • value1과 value2 사이의 WHERE 필드
  • 작은 조인은 좋은 조인입니다
    • 기본적으로 옵티마이 저는 한 번에 테이블 4 만 고려합니다.
    • 이는 4 개 이상의 테이블과 조인 할 때 최적이 아닌 쿼리 계획을 선택할 가능성이 있음을 의미합니다.
  • 조인 해체
    • 조인을 끊을 수 있습니까?
    • 외래 키를 임시 테이블로 미리 선택
    • 조인의 절반을 수행하고 결과를 임시 테이블에 넣습니다.
  • 올바른 종류의 임시 테이블을 사용하고 있습니까?
    • #temp테이블은 @table많은 양 (수천 행)의 변수 보다 훨씬 성능이 좋을 수 있습니다 .
  • 요약 테이블 유지
    • 기본 테이블에서 트리거로 빌드
    • 매일 / 시간별 / 등을 만듭니다.
    • 임시 빌드
    • 점진적으로 구축 또는 분해 / 재 구축
  • SET SHOWPLAN ON을 사용한 쿼리 계획 확인
  • SET STATS IO ON으로 실제로 어떤 일이 일어나고 있는지 확인
  • pragma를 사용하여 색인을 강제 실행하십시오. (index : myindex)
  • SET FORCEPLAN ON을 사용하여 테이블 순서 강제
  • 매개 변수 스니핑 :
    • 저장 프로 시저를 2로 나누기
    • proc1에서 proc2를 호출
    • proc1에서 @parameter를 변경 한 경우 옵티마이 저가 proc2에서 인덱스를 선택할 수 있도록합니다.
  • 하드웨어를 향상시킬 수 있습니까?
  • 몇시에 뛰니? 조용한 시간이 있습니까?
  • Replication Server (또는 기타 논스톱 프로세스)가 실행 중입니까? 일시 중지 할 수 있습니까? 예를 들어 실행하십시오. 매시간?

2
당신은 어느 비트를 참조하고 있습니까?
AJ.

2
이것은 멋진 것들이지만 일부 주장에 대한 참고 자료가 있기를 바랍니다. 예를 들어, 최적화에서 조인에서 한 번에 4 개의 테이블 만 고려한다고 들었습니다. 이것이 어떻게 옳은지 이해하지 못합니다. 특히 그것에 대한 몇 가지 참조를 제공 할 수 있습니까? 나는 당신이 이것을 얻는 곳을보고 싶습니다.
SheldonH

19
  1. 머리 속에서 쿼리를 실행하는 최적의 경로를 잘 알고 있어야합니다.
  2. 항상 쿼리 계획을 확인하십시오.
  3. STATS를 켜서 IO 및 CPU 성능을 모두 검사 할 수 있습니다. 쿼리 시간이 아닌 숫자를 줄이는 데 집중하십시오 (다른 활동, 캐시 등의 영향을받을 수 있음).
  4. 연산자에 많은 수의 행이 있지만 작은 숫자가 나오는지 찾으십시오. 일반적으로 인덱스는 들어오는 행 수를 제한하여 디스크 읽기를 절약하는 데 도움이됩니다.
  5. 가장 큰 비용 하위 트리에 먼저 중점을 둡니다. 하위 트리를 변경하면 종종 전체 쿼리 계획이 변경 될 수 있습니다.
  6. 내가 본 일반적인 문제는 다음과 같습니다.
    • 조인이 많으면 Sql Server가 조인을 확장 한 다음 WHERE 절을 적용하도록 선택하는 경우가 있습니다. 일반적으로 WHERE 조건을 JOIN 절로 이동하거나 조건이 인라인 된 파생 테이블로 이동하여이 문제를 해결할 수 있습니다. 뷰가 동일한 문제를 일으킬 수 있습니다.
    • 차선 조인 (LOOP vs HASH vs MERGE). 내 경험상 맨 위 행이 맨 아래 행과 비교할 때 행이 거의 없을 때 LOOP 조인을 사용하고, 세트가 대략 동일하고 정렬 된 경우 MERGE, 기타 모든 항목에 대해 해시를 사용합니다. 조인 힌트를 추가하면 이론을 테스트 할 수 있습니다.
    • 매개 변수 스니핑. 테스트를 위해 처음에 비현실적인 값으로 저장된 proc을 실행 한 경우 캐시 된 쿼리 계획이 프로덕션 값에 대해 차선책 일 수 있습니다. WITH RECOMPILE을 다시 실행하면이를 확인해야합니다. 일부 저장된 procs의 경우, 특히 다양한 크기의 범위 (예 : 오늘부터 어제까지의 모든 날짜-INDEX SEEK를 수반하는 모든 날짜 또는 작년과 올해의 모든 날짜)를 다루는 INDEX SCAN을 사용하는 것이 좋습니다 ) 매번 RECOMPILE을 실행해야 할 수도 있습니다.
    • 들여 쓰기가 잘못되었습니다. 좋아요. 그래서 Sql Server는 이것에 문제가 없지만 형식을 고칠 때까지 쿼리를 이해하는 것이 불가능하다는 것을 알았습니다.

1
들여 쓰기가 잘못되면 +1 서식이 핵심입니다! :)
mwigdahl

18

주제를 약간 벗어 났지만 이러한 문제를 제어 할 수있는 경우 ...
높은 수준 및 높은 영향.

  • IO가 높은 환경에서는 디스크가 RAID 10 또는 RAID 0 + 1 또는 raid 1 및 raid 0의 일부 중첩 구현 용인지 확인하십시오.
  • 1500K 미만의 드라이브를 사용하지 마십시오.
  • 디스크가 데이터베이스에만 사용되는지 확인하십시오. IE는 로깅이 없으며 OS가 없습니다.
  • 자동 증가 또는 유사한 기능을 끕니다. 데이터베이스가 예상되는 모든 스토리지를 사용하도록하십시오. 반드시 현재 사용되고있는 것은 아닙니다.
  • 형식 쿼리에 대한 스키마 및 인덱스를 디자인하십시오.
  • 로그 유형 테이블 인 경우 (삽입 전용) DB에 있어야하며 인덱스하지 않아야합니다.
  • 보고 할당을 수행하는 경우 (복잡한 조인이 많은 복잡한 선택) 스타 또는 눈송이 스키마를 사용하여 데이터웨어 하우스를 작성해야합니다.
  • 성능을 대가로 데이터를 복제하는 것을 두려워하지 마십시오!

8

CREATE INDEX

WHEREJOIN조항에 사용할 수있는 색인이 있는지 확인하십시오 . 이렇게하면 데이터 액세스 속도가 크게 향상됩니다.

환경이 데이터 마트 또는웨어 하우스 인 경우 거의 모든 쿼리에 대해 인덱스가 풍부해야합니다.

A의 트랜잭션 환경 이 인덱스 유지 관리 자원을 아래로 드래그하지 않도록, 인덱스의 수는 낮은 및 그 정의 전략적이어야한다. (인덱스 유지 관리는 기본 테이블의 변경 사항 INSERT, UPDATE,DELETE작업 을 반영하여 인덱스의 리프를 변경해야하는 경우 입니다.)

또한 색인에서 필드의 순서를 명심하십시오. 필드가 더 선택적 일수록 (더 높은 카디널리티) 색인에서 더 일찍 나타납니다. 예를 들어 중고차를 검색한다고 가정 해 보겠습니다.

SELECT   i.make, i.model, i.price
FROM     dbo.inventory i
WHERE    i.color = 'red'
  AND    i.price BETWEEN 15000 AND 18000

가격은 일반적으로 카디널리티가 더 높습니다. 사용 가능한 색상은 수십 가지에 불과하지만 수천 가지 다른 가격이 있습니다.

이러한 인덱스 선택 중에서 idx01쿼리를 충족시키는 더 빠른 경로를 제공하십시오.

CREATE INDEX idx01 ON dbo.inventory (price, color)
CREATE INDEX idx02 ON dbo.inventory (color, price)

이는 색상 선택보다 가격대를 만족시키는 자동차 수가 적기 때문에 쿼리 엔진이 분석 할 데이터가 훨씬 적기 때문입니다.

필드 순서에서만 다른 두 개의 매우 유사한 인덱스를 사용하여 하나의 쿼리 (이름, 성)와 다른 하나의 (성, 이름)을 가속화하는 것으로 알려져 있습니다.


6

최근에 배운 요령은 SQL Server가 업데이트 문에서 필드뿐만 아니라 로컬 변수도 업데이트 할 수 있다는 것입니다.

UPDATE table
SET @variable = column = @variable + otherColumn

또는 더 읽기 쉬운 버전 :

UPDATE table
SET
    @variable = @variable + otherColumn,
    column = @variable

나는 이것을 재귀 계산을 구현할 때 복잡한 커서 / 조인을 대체하기 위해 사용했으며 성능도 많이 얻었습니다.

성능을 크게 향상시킨 세부 사항 및 예제 코드는 다음과 같습니다. http://geekswithblogs.net/Rhames/archive/2008/10/28/calculating-running-totals-in-sql-server-2005---the-optimal. aspx


5

여기에 MySQL이 있다고 가정하면 EXPLAIN을 사용하여 쿼리에서 수행중인 작업을 찾고 인덱스가 가능한 한 효율적으로 사용되고 있는지 확인하고 파일 정렬을 제거하십시오. 고성능 MySQL : 최적화, 백업, 복제 등MySQL 성능 블로그마찬가지로이 주제에 대한 훌륭한 책입니다 .


3
MySQL에는 좋지만 질문에는 "sqlserver"라는 태그가 붙어 있습니다. 그래도 그렇게하는 것이 좋습니다. SSMS에서 유사한 작업은 "예상 실행 계획 표시"및 "실제 실행 계획 포함"을 사용하는 것입니다. 대량의 테이블 스캔을 제거하고 클러스터 된 인덱스 검색을 사용할 수 있다면 최적의 성능을 발휘할 수 있습니다.
eksortso

5

@ Terrapin은 언급 할 가치가있는 isull과 coalesce 사이에 몇 가지 다른 차이점이 있습니다 (ANSI 준수 이외에도 큰 문제입니다).

Coalesce vs. IsNull


3

SQL Server에서 where 절에 OR을 사용하면 실제로 성능에 영향을 미칩니다. OR을 사용하는 대신 두 가지 선택을 수행하고 함께 결합하십시오. 1000 배속에서 동일한 결과를 얻습니다.


나는이 설명 할 수없는 행동을 보았다.
Esen

2

where 절을보십시오-인덱스 사용을 확인하십시오.

where SomeComplicatedFunctionOf(table.Column) = @param --silly

2

나는 일반적으로 조인으로 시작할 것이다-나는 문제가있는 특정 조인이 있다면 아이디어를 얻기 위해 쿼리를 한 번에 하나씩 중단하고 쿼리를 다시 실행합니다.


2

모든 임시 테이블에서 인덱스를 만들기 위해 고유 제약 조건 (적절한 경우)과 기본 키 (거의 항상)를 추가하고 싶습니다.

declare @temp table(
    RowID int not null identity(1,1) primary key,
    SomeUniqueColumn varchar(25) not null,
    SomeNotUniqueColumn varchar(50) null,
    unique(SomeUniqueColumn)
)

2

항상 바인드 변수를 사용하는 습관을 들였습니다. RDBMS가 SQL 문을 캐시하지 않으면 바인드 변수가 도움이되지 않을 수 있습니다. 그러나 바인드 변수를 사용하지 않으면 RDBMS는 쿼리 실행 계획 및 구문 분석 된 SQL 문을 재사용 할 기회가 없습니다. : 저축은 엄청난 수 있습니다 http://www.akadia.com/services/ora_bind_variables.html . 나는 주로 Oracle과 함께 일하지만 Microsoft SQL Server는 거의 같은 방식으로 작동합니다.

내 경험에 따르면 바인드 변수를 사용하는지 여부를 모른다면 아마도 사용하지 않을 것입니다. 응용 프로그램 언어가 지원하지 않는 언어를 찾으십시오. 때때로 쿼리 B에 대한 바인드 변수를 사용하여 쿼리 A를 수정할 수 있습니다.

그 후, 나는 DBA와 대화하여 RDBMS가 가장 고통스러운 원인을 찾아냅니다. "이 쿼리가 왜 느린가요?"라는 질문을하지 않아야합니다. 의사에게 부록을 꺼내달라고 요청하는 것과 같습니다. 쿼리가 문제가 될 수는 있지만 다른 문제가 발생했을 가능성이 높습니다. 개발자로서 우리는 코드 라인의 관점에서 생각하는 경향이 있습니다. 회선이 느리면 해당 회선을 수정하십시오. 그러나 RDBMS는 매우 복잡한 시스템이므로 느린 쿼리는 훨씬 더 큰 문제의 증상 일 수 있습니다.

너무 많은 SQL 튜닝 팁은화물 컬트 우상입니다. 대부분의 경우 문제는 사용하는 구문과 관련이 없거나 최소한의 관련성이 있으므로 일반적으로 가능한 가장 깨끗한 구문을 사용하는 것이 가장 좋습니다. 그런 다음 쿼리가 아닌 데이터베이스를 튜닝하는 방법을 살펴볼 수 있습니다. 실패하면 구문을 조정하십시오.

다른 성능 조정과 마찬가지로 항상 의미있는 통계를 수집하십시오. 튜닝하는 사용자 경험이 아닌 한 벽시계 시간을 사용하지 마십시오. 대신 CPU 시간, 페치 된 행 및 디스크 읽기 차단과 같은 것을보십시오. 너무 자주 사람들이 잘못된 것을 최적화합니다.


2

첫 번째 단계 : 쿼리 실행 계획을보십시오!
TableScan-> 잘못된
NestedLoop-> meh 경고
NestedLoop 뒤에 TableScan-> DOOM!

통계 IO
설정 통계 시간 설정


2

WITH (NoLock)을 사용하여 쿼리를 실행하는 것은 제 자리에서 거의 표준 작업입니다. 누구든지 수십 기가 바이트 테이블에서 쿼리를 실행하지 않고 가져 와서 처리하지 못했습니다.


2
이것은 습관적으로가 아니라 신중하게 사용해야합니다. 잠금은 악이 아니라 오해입니다.

2

가능하면 NOT IN 쿼리를 왼쪽 외부 조인으로 변환하십시오. 예를 들어 Table2의 외래 키에서 사용하지 않는 Table1의 모든 행을 찾으려면 다음과 같이하십시오.

SELECT *
FROM Table1
WHERE Table1.ID NOT IN (
    SELECT Table1ID
    FROM Table2)

그러나 이것으로 훨씬 더 나은 성능을 얻을 수 있습니다.

SELECT Table1.*
FROM Table1
LEFT OUTER JOIN Table2 ON Table1.ID = Table2.Table1ID
WHERE Table2.ID is null

1

@ 데이빗

여기에 MySQL이 있다고 가정하면 EXPLAIN을 사용하여 쿼리 진행 상황을 확인하고 인덱스가 가능한 한 효율적으로 사용되는지 확인하십시오 ...

SQL Server에서 실행 계획은 같은 것을 얻습니다. 어떤 인덱스가 히트되는지 등을 알려줍니다.



1

SQL 성능 트릭 자체는 아니지만 반드시 관련이 있습니다.

사전 컴파일 된 데이터를 데이터베이스에서 가져 오는 대신 메모리에서 직접 가져 오는 것이 훨씬 빠르기 때문에 가능한 경우 memcached를 사용하는 것이 좋습니다. memcached (타사)를 내장 한 MySQL의 특징도 있습니다.


1

색인 길이가 최대한 작아야합니다. 이를 통해 DB는 파일 시스템에서 한 번에 더 많은 키를 읽을 수 있으므로 결합 속도가 빨라집니다. 나는 이것이 모든 DB에서 작동한다고 가정하지만 MySQL에 대한 특정 권장 사항이라는 것을 알고 있습니다.


1

나는 다음을 찾습니다.

  • CURSOR 루프를 풀고 세트 기반 UPDATE / INSERT 문으로 변환하십시오.
  • 다음과 같은 애플리케이션 코드를 찾으십시오.
    • 큰 레코드 집합을 반환하는 SP를 호출합니다.
    • 그런 다음 응용 프로그램에서 각 레코드를 살펴보고 매개 변수가있는 SP를 호출하여 레코드를 업데이트합니다.
    • 이것을 하나의 트랜잭션으로 모든 작업을 수행하는 SP로 변환하십시오.
  • 많은 문자열 조작을 수행하는 모든 SP 데이터가 올바르게 구성 / 정규화되지 않았다는 증거입니다.
  • 바퀴를 재발 명하는 모든 SP.
  • SP가 1 분 안에 무엇을하려고하는지 이해할 수없는 SP입니다!

1
SET NOCOUNT ON

실제로 사용하지 않는 한 일반적으로 저장 프로 시저 내부의 첫 번째 줄 @@ROWCOUNT입니다.


2
@@ ROWCOUNT는 어쨌든 설정됩니다. NOCOUNT는 "xx rows 영향을받는"문을 비활성화합니다.
Sklivvz

이것이 실제로 성능에 상당한 차이를 만들어 줍니까?
JohnFx

그렇다면 SQL 문을 실행할 때마다 카운트가 자동으로 계산되지 않습니다. 차이가 있는지 확인하기 위해 쿼리를 벤치마킹하기에 충분합니다.
트래비스

어쨌든 수는 SQL Server에서 추적됩니다. 성능 차이는 네트워크를 통해 프런트 엔드로 이동해야하기 때문입니다. 단일 SELECT를 수행하면 큰 차이가 없습니다. 100000 개의 인서트가있는 루프가 있으면 네트워크를 통해 훨씬 더 많이 추가됩니다.
Tom H

1

SQL Server에서는 nolock 지시문을 사용하십시오. 기다리지 않고 select 명령을 완료 할 수 있습니다. 일반적으로 다른 트랜잭션을 완료합니다.

SELECT * FROM Orders (nolock) where UserName = 'momma'

3
NOLOCK은 정확한 결과에 신경 쓰지 않는 쿼리에 대해서만
Mark Sowul

1

필요하지 않은 곳에서는 커서를 제거하십시오.


예, 커서는 저주입니다! ;)
Sklivvz

8
어. 그렇게 규정되지 않은 것을 버리지 마십시오. 커서는 총과 같습니다. 그들은 스스로 나쁘지 않습니다. 사람들이 실제로 나쁜 일을한다는 것입니다.
JohnFx

1

많은 행이 함수를 호출하는 Sprocs에서 함수 호출을 제거하십시오.

동료가 함수 호출 (예 : userid에서 lastlogindate를 가져옴)을 사용하여 매우 광범위한 레코드 세트를 반환했습니다.

최적화 작업을 수행하면서 sproc의 함수 호출을 함수 코드로 대체했습니다. 많은 sprocs 실행 시간이 20 초에서 <1로 줄었습니다.


0
  • 모든 테이블 앞에 dbo를 붙입니다. 재 컴파일을 방지합니다.
  • 쿼리 계획을보고 테이블 / 인덱스 검색을 찾습니다.
  • 2005 년에는 누락 된 인덱스에 대한 관리 뷰를 검색하십시오.


0

시스템 프로시 저는 모두 "sp_"로 시작하고 저장 프로 시저 이름은 "sp_"로 시작하지 않으며 SQL Server는 프로 시저가 호출 될 때 프로 시저를 찾기 위해 더 열심히 검색해야합니다.


1
실제로 이것을 벤치마킹 했습니까? SQL Server가 해시 알고리즘을 사용하여 Stored Proc를 찾는 합리적인 작업을 수행하는 경우 아무런 차이가 없습니다. 실제로 SQL Server 그렇게 하지 않으면 시스템 성능이 저하되는 것처럼 보입니다 (아마도 자체 프로세서라고 부름).
John Stauffer

1
나는 이것이 조기 최적화의 양동이에 빠졌다고 생각합니다. 사람들에게 혼란을 피하는 것이 좋은 습관 일 것입니다. 그러나 최적화 팁으로 ... D-
JohnFx

0

더티 읽기 -

set transaction isolation level read uncommitted

트랜잭션 무결성이 절대적으로 필요하지 않은 데드락 방지 (일반적으로 해당됨)


1
예, 그러나 이것은 매우 찾기 어려운 이상한 버그로 이어질 수 있습니다.
Grant Johnson

0

나는 항상 SQL 프로파일 러 (내포 수준이 많은 저장 프로 시저 인 경우) 또는 쿼리 실행 플래너 (중첩이없는 SQL 문이 몇 개인 경우)로 먼저 이동합니다. 90 %의 시간 동안이 두 도구 중 하나를 사용하여 문제를 즉시 찾을 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.