로드시 인서트 성능 향상 : 왜?


19

고도로 표준화되지 않은 테이블에 삽입을 수행하는 코드가 있습니다. 테이블에는 ~ 100에서 300+ 범위의 열 수가 있습니다. 이것은 Windows Server 2008에서 실행되는 SQL Server 2008 R2입니다.

각 삽입은 동일한 트랜잭션에서 여러 테이블에 삽입하는 것으로 구성됩니다. 일부 인서트는 NHibernate에 의해 일괄 처리되지만 일부 인서트는 배치 할 수 없지만 그럼에도 불구하고 모두 동일한 트랜잭션에 있습니다.

삽입을 수행하는 코드를 반복해서 호출하여 500 회 삽입을 수행하면 평균 ~ 360ms가됩니다.

이상한 점은 4 개의 프로세스 (Windows Server 2008의 4 가지 명령 프롬프트에서 실행되는 동일한 exe)를 사용하여 테스트 코드를 동시에 실행하면 호출 당 삽입 성능이 훨씬 좋아집니다. 90ms (거의 X4 빠름)만큼 빠른 버스트가 보입니다. 코드에서 삽입 시간을 측정하고 있습니다.

4 개의 프로세스는 서로에 대해 아무것도 모르기 때문에 이것이 SQL Server와 관련이 있다고 가정하지만 그 이유는 전혀 없습니다. 인서트가 그다지 빈번하지 않을 때 동일한 성능을 얻을 수있는 구성이 있는지, 왜 이런 일이 발생하는지 알고 싶습니다.

DB 수준에서 무슨 일이 일어나고 있는지 이해하기위한 SQL Server 모니터링 방법에 대한 제안도 환영합니다.

답변:


15

가능한 한 가지 이유는 4 개의 동시 프로세스가보다 바람직한 로그 플러시 패턴을 생성하기 때문입니다. 일반적으로 각 로그 플러시는 단일 실행 프로세스의 경우보다 더 많은 데이터를 씁니다.

트랜잭션 로그 처리량 / 플러시 크기가 요인인지 확인하려면 다음을 모니터링하십시오.

내부 한계에 도달했는지 확인하십시오. SQL Server 2008 R2에서는 64 비트 버전에서 데이터베이스 당 최대 32 개의 미해결 (비동기) 로그 플러시 I / O가있을 수 있습니다 (32 비트에서는 8 개만). 3840KB의 미해결 IO에 대한 총 크기 제한도 있습니다.

추가 정보 및 추가 정보 :


12

@PaulWhite의 모든 것 플러스 ...

외래 키가있는 경우 모든 삽입은 참조 된 각 테이블에서 검사를 수행해야합니다. 당신이 360ms 만 받고 있기 때문에 나에게 느리게 느껴집니다.

어쨌든, 테이블을 검사하는 것은 디스크에 데이터를로드하지 않고 RAM에 이미 데이터를 저장함으로써 크게 도움이됩니다.

RAM에 데이터를로드하는 것은 실행의 중요한 부분이며 한 번만 수행하면된다는 것처럼 들립니다.

또한 효과적인 계획 캐싱이 가능하며 후속 호출에서 해당 단계를 피할 수 있도록 쿼리를 처음으로 컴파일해야합니다.


고마워 Rob. 내 성능 문제는 삽입 중에 사용 된 많은 수의 테이블과 관련이 있습니다. 외래 키가 없으며 성능상의 이유로 키를 제거했으며 내 모델 및 도메인 요구 사항에 따라 가능합니다. 데이터를 RAM에로드하지 않고 있으며, 인서트는 들어오는 요청에 따라 동적으로 변경됩니다. 기본적으로 OLTP에 대한 별 / 눈송이 (ish) 스키마를 잘못 사용하고 가능한 최고의 성능으로 도망치려 고합니다.
mahonya

2
@mahonya, 명시 적으로 RAM에 데이터를로드하지 않더라도 SQL Server는 삽입 작업을 수행하기 전에 먼저 필요한 인덱스와 데이터 페이지를 버퍼 캐시로 읽어야합니다. 동시 삽입 스레드는 하나의 스레드가 읽기 오버 헤드를 발생시키고 다른 하나는 캐시의 데이터에 액세스하도록 캐시를 예열하는 효과를 가질 수 있습니다.
Dan Guzman

@DanGuzman에게 감사합니다-그리고 그렇습니다. mahonya, 캐시가 멋지게 따뜻해질 가능성이 높습니다. 물리적 I / O가 병목 현상을 일으키는 지 확인하기 위해 대기를 확인하고 있습니다.
Rob Farley

@DanGuzman Agreed에게 감사드립니다. db 인덱스 캐시 속도 향상은 postgres에서 Rob의 입력을 오해했을 것입니다.
mahonya

-3

일부 서버 / CPU / OS는 패턴을 기억합니다. 캐시처럼.

동일한 작업을 4 번 수행했기 때문에 모서리를자를 수있는 방법이 있다고 확신합니다. 제 생각에 첫 번째 방법은 하나의 긴 프로세스 (example1)이지만 두 번째 방법으로 생각한다는 것입니다 는 재사용 된 코드를보고 캐시처럼 실행하거나 (example2) 첫 번째 프로세스가 (ram example3)에 모두 들어가는 것입니다.

예 1 : 0111110000110111110000111011111000011110111110000

예 2 : 0111110000 | 11 | 0111110000 | 111 | 0111110000 | 1111 | 0111110000

예 3 : 0111110000011111000001111100000111110000 예 3 : 루프 : 0111110000

우분투 서버가 반복적 인 mysql 쿼리 로이 작업을 수행한다는 것을 알고 있습니다. 실제로 시간의 유일한 차이는 10-40mm이지만 캐시에 저장할 수는 있습니다. 내가 학교에있을 때 프로그램 (perl / php)이 그 캐시를 더 빨리 사용하도록 만들어야하는 수업이있었습니다.

그러나 프로그램, 언어, 컴파일 및 프로그래밍 방법에 따라 달라질 수 있습니다.

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