SQL Server 쿼리가 메모리에서 실행되고 있는지 또는 디스크로 이동하는지 확인할 수있는 방법이 있습니까?


13

오늘날 응용 프로그램에서 장기 실행 프로세스 내에서 반복적으로 호출되는 일련의 저장 프로 시저를 발견했습니다. 각 절차 내에서 여러 개의 다른 select 문을 발견했습니다. 당연히 현재 사용되는 이러한 루틴을 실행하는 데 몇 분이 걸리며, 직감으로 인해 몇 초 안에 완료 될 것으로 예상됩니다.

이러한 절차를 작성할 때 성능이 고려되지 않았 음을 알 수 있습니다. "좋은 생각이 아닌"여러 가지 사례가 있습니다.

데이터를 가져올 때 각 행을 처리하는 데 행당 300ms가 걸리므로 비교적 작은 가져 오기가 처리하는 데 몇 분이 걸립니다.

그러나 절차와 관련된 표는 대부분 매우 작습니다. 나는이 모든 테이블이 완전히 메모리에 상주한다면 아마도 이것을 다시 써서 얻을 수있는 것이 많지 않을 것이라고 생각합니다.

나는이 비효율적 인 코드를 결정하려고 노력하고 있는데, 실제로 얼마나 많은 영향을 미칩니 까? 고칠 가치가 있습니까?

따라서 질문은 다음과 같습니다
.-메모리에 어떤 테이블이 완전히 고정되어 있는지 확인할 수있는 방법이 있습니까?
-특히 값 비싼 부분을 찾기 위해 중첩 된 저장 프로 시저를 모니터링하기 위해 추적을 설정하는 방법이 있습니까?

참고 : 이것은 SQL Server 2008 R2에 있습니다.

답변:


12

이 두 쿼리 중 하나를 사용하여 총 논리적 읽기 및 총 물리적 읽기를 볼 수 있습니다.

SELECT  DB_NAME(st.dbid) Db,
        OBJECT_NAME(st.objectid, st.dbid) Prc,
        qs.execution_count,
        qs.total_logical_reads,
        qs.total_physical_reads,
        qs.statement_start_offset,
        qs.statement_end_offset,
        st.text
FROM    sys.dm_exec_query_stats qs
CROSS APPLY sys.dm_exec_sql_text(qs.sql_handle) st;

SELECT  DB_NAME(database_id) Db,
        OBJECT_NAME(object_id, database_id) Prc,
        execution_count,
        total_logical_reads,
        total_physical_reads
FROM    sys.dm_exec_procedure_stats ps;

첫 번째는 이것을 진술로 세분화하고, 두 번째는 전체 절차에서 계산합니다.

물리적 읽기는 디스크에 대한 읽기이고 논리적 읽기는 메모리에 대한 읽기입니다. 이를 사용하여 시스템에서 가장 비싼 프로 시저 또는 명령문을 파악하고 튜닝 할 수 있습니다.

논리적 읽기는 물리적 읽기보다 훨씬 저렴하지만 여전히 비싸므로 (예를 들어 적절한 색인을 추가하여) 읽기 수를 줄이면 쿼리 실행 속도가 훨씬 빨라질 수 있습니다.

위의 DMV에는 흥미로운 추가 열이 많이 있습니다.


인덱스는 논리적 읽기를 줄이는 데 어떻게 도움이됩니까?

SQL Server에서 모든 데이터는 8KB 크기의 블록으로 구성됩니다. 이러한 블록을 "페이지"라고합니다.

모든 테이블에는 파타 페이지뿐만 아니라 테이블 구조에 대한 정보가 포함 된 "메타"페이지가 포함됩니다. 인덱스가없고 SELECT * FROM tbl WHERE Id = 7SQL Server 와 같은 쿼리를 실행 하면 전체 테이블에서이 행 또는이 행을 찾아야합니다. 따라서 한 번에 한 페이지 씩 읽고 각 페이지의 모든 행을 반복하여 WHERE절에 맞는 행을 결정합니다 . 따라서 테이블에 1,000,000 페이지를 저장해야하는 경우이 쿼리를 실행하려면 1,000,000 개의 논리적 읽기가 필요합니다.

인덱스가있는 경우 SQL Server는 페이지 내에서 데이터를 논리적으로 정렬하고 페이지간에 연결된 목록을 설정합니다. 이를 통해 ORDER BY값 비싼 정렬 작업없이 쿼리를 실행할 수 있습니다. 그러나 중요한 점은 정렬, SQL Server가 B + Tree 를 테이블에 추가한다는 것 입니다. B + 트리는 책의 색인과 비교할 수있는 구조로 특정 키워드를 찾으면 키워드가 포함 된 페이지로 바로 이동할 수 있습니다. 일반적인 책은 색인 수준이 하나 뿐인 반면 B + Tree는 여러 수준을 가질 수 있습니다. 색인 자체가 여러 페이지 인 큰 책을 생각해보십시오. 이와 같은 경우 추가 색인 레이어를 추가하면 어느 페이지에서든 시작하는 색인 ​​단어 S를 찾을 수 있습니다.

B + Tree는 가능한 한 적은 수의 레벨을 갖도록 최적화되며 인덱스 레벨 당 한 페이지를 읽어 인덱스의 모든 레코드를 찾을 수있는 특성을 제공합니다. 따라서을 기준 WHERE Id = 7으로 인덱스를 정렬 한 경우 위 쿼리를 가정하십시오 Id. 지수가 5 단계라고 가정 해 봅시다. 이제이 쿼리와 일치하는 모든 레코드를 찾으려면 인덱스 수준 당 한 페이지 (5 페이지)를 읽어야합니다.이를 "인덱스 찾기"라고합니다. 청구서에 맞는 여러 레코드가있는 경우 정렬 된 색인을 따라 가서 모든 레코드를 검색해야 할 수도 있습니다. 그러나 레코드가 하나만 있다고 가정합니다.

따라서 인덱스를 실행하지 않으면 해당 쿼리에 1,000,000 회의 읽기가 필요했으며 실제로는 5 회의 읽기가 필요했습니다. 논리적 읽기는 메모리 내 작업이지만 상당한 비용이 발생합니다. 실제로 위와 같은 간단한 쿼리에서 가장 비싼 작업입니다. 따라서 200,000 배로 필요한 논리적 읽기 양을 줄이면 비슷한 요소로 쿼리 속도가 빨라집니다.

따라서 논리적 읽기는 테이블 스캔과 동일하지 않지만 테이블 스캔은 인덱스 검색보다 훨씬 많은 논리적 읽기를 발생시킵니다.


> "... 적절한 인덱스를 추가하는 등의 횟수를 줄이면 쿼리 실행 속도가 훨씬 빨라질 수 있습니다." 인덱스를 추가하면 논리적 읽기가 어떻게 줄어드는 지 설명 할 수 있습니까? 논리적 읽기는 테이블 스캔과 동의어입니까?

1
위의 답변에 설명을 추가했습니다.
Sebastian Meine

감사. 적절한 인덱스가 관련된 모든 테이블에 있다고 가정하더라도 ... 메모리에 고정 된 테이블과 디스크에서 읽은 테이블 (두 시나리오에서 동일한 인덱스를 가정) 또는 다른 테이블 사이에는 여전히 상당한 성능 차이가 있다고 생각합니다. 즉, 인덱스를 추가하면 메모리가 적은 컴퓨터보다 RAM이 많은 컴퓨터에서 성능이 % 향상되지 않습니다.

1
물리 디스크 액세스는 메모리 액세스보다 훨씬 비쌉니다. 따라서이를 피하기위한 조치를 취하면 매우 멀리 갈 수 있습니다. 쿼리 튜닝시 여전히 논리적 읽기 수를 먼저 확인해야합니다. 이를 낮게 유지하면 물리적 읽기를 낮게 유지합니다. 또한 캐시에서 페이지를 제거 할 필요가 없어 필요한 실제 읽기를 훨씬 더 줄일 수 있습니다.
Sebastian Meine

2
작은 nitpick-페이지가 8kb라고 생각합니다 :-). 좋은 대답입니다.
onupdatecascade

3
  • 특히 값 비싼 부분을 찾기 위해 중첩 저장 프로 시저를 모니터링하기 위해 추적을 설정하는 방법이 있습니까?

SQL 프로파일 러를 사용할 수 있습니다. 추적을 시작할 때 RPC Completed, SP Starting, SP StmtStarting 및 SP StmtCompleted를 선택해야합니다 (아래 이미지 참조).

여기에 이미지 설명을 입력하십시오

그러면 저장 프로 시저 내에서 실행되는 모든 쿼리를 볼 수 있습니다. 중첩 저장 프로 시저가 몇 번 호출되는지 확인할 수 있습니다. 추적이 끝나면 저장해야합니다. 그런 다음 다시 열면 문제를 일으키는 쿼리를 찾기 위해 "열 필터"단추를 사용하여 필터링 할 수 있습니다. (예 : x 회 이상 읽거나 x 초 이상 지속 된 쿼리 (지속 시간) ...)

내가 보여준 프로파일 러 옵션도 실행 계획을 보여줍니다. 또한 많은 도움이됩니다.


1

일반적인 쿼리 최적화 질문처럼 보입니다. 당신의 설명에서 나는 :

  1. 코드가 행 단위로 처리되는지 확인하십시오. 그렇다면 세트 (동시에 여러 행이 처리됨)를 사용하여 동일한 논리를 구현하여 수십 배의 개선이 이루어질 수 있습니다. 다시 말해, "각 행에 루프"처럼 작동하면 "모든 행 처리"로 변경하십시오. 옵티마이 저는 가능한 많은 방법 중에서 선택하고, 병렬 처리를 사용하고, 한 번에 한 행씩 발생 하는 많은 오버 헤드를 제거 할 수 있기 때문에 SQL이 뛰어납니다 .
  2. 다음으로 작업을 지원하는 색인이 있는지 확인하십시오. 종종, 또 다시, 정확한 지수 대 그렇지 않은 경우에 수차 개선이 이루어질 수있다. 이것은 메모리와 디스크 액세스에서 마찬가지입니다. 큰 데이터 세트에 적절한 인덱스가없는 경우 RAM의 모든 항목을 처리하는 데 여전히 몇 시간이 걸릴 수 있습니다.
  3. 다음으로, 설정된 논리와 인덱스를 사용하여 영향을받는 데이터 페이지가 메모리에 맞는지 살펴 보겠습니다. 이 시점에서 디스크 액세스가 여전히 많은 경우 물리적 읽기 및 디스크 활동을 살펴 보는 것이 합리적입니다. 최적화의 모든 큰 이점은 처음 두 단계에서 수행되기 때문입니다.
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.