인 메모리 테이블의 성능이 디스크 기반 테이블보다 나쁩니다.


10

SQL Server 2014에는 다음과 같은 테이블이 있습니다.

CREATE TABLE dbo.MyTable
(
[id1] [bigint] NOT NULL,
[id2] [bigint] NOT NULL,
[col1] [int] NOT NULL default(0),
[col2] [int] NOT NULL default(0)
)

(id1, id2)는 PK입니다. 기본적으로 id1은 pk가 id2 인 결과 집합 (id2, col1, col2)을 그룹화하는 식별자입니다.

병목 현상 인 기존 디스크 기반 테이블을 제거하기 위해 메모리 내 테이블을 사용하려고합니다.

  • 테이블의 데이터는 기록-> 읽기-> 한 번 삭제됩니다.
  • 각 id1 값에는 수천 개의 id2가 있습니다 (수십 / 수백).
  • 데이터는 매우 짧은 시간 (예 : 20 초) 동안 테이블에 저장됩니다.

이 테이블에서 수행 된 쿼리는 다음과 같습니다.

-- INSERT (can vary from 10s to 10,000s of records):
INSERT INTO MyTable
  SELECT @fixedValue, id2, col1, col2 FROM AnotherTable

-- READ:
SELECT id2, col1
FROM MyTable INNER JOIN OtherTbl ON MyTable.id2 = OtherTbl.pk
WHERE id1 = @value
ORDER BY col1

-- DELETE:
DELETE FROM MyTable WHERE id1 = @value

테이블에 사용한 현재 정의는 다음과 같습니다.

CREATE TABLE dbo.SearchItems
(
  [id1] [bigint] NOT NULL,
  [id2] [bigint] NOT NULL,
  [col1] [int] NOT NULL default(0),
  [col2] [int] NOT NULL default(0)

  CONSTRAINT PK_Mem PRIMARY KEY NONCLUSTERED (id1,id2),
  INDEX idx_Mem HASH (id1,id2) WITH (BUCKET_COUNT = 131072)
) WITH (MEMORY_OPTIMIZED = ON, DURABILITY = SCHEMA_ONLY)

불행히도,이 정의는 디스크 기반 테이블의 이전 상황과 관련하여 성능이 저하됩니다. 크기 차수는 10 % 정도 더 높거나 적습니다 (일부 경우 100 %에 도달하므로 더블 타임).

무엇보다도 Microsoft가 광고하는 잠금없는 아키텍처를 고려할 때 동시성 시나리오에서 뛰어난 이점을 얻을 것으로 기대했습니다. 대신 최악의 성능은 테이블에서 여러 쿼리를 실행하는 여러 명의 동시 사용자가있을 때입니다.

질문 :

  • 올바른 BUCKET_COUNT는 무엇입니까?
  • 어떤 종류의 색인을 사용해야합니까?
  • 디스크 기반 테이블보다 성능이 떨어지는 이유는 무엇입니까?

sys.dm_db_xtp_hash_index_stats 의 쿼리 는 다음을 반환합니다.

total_bucket_count = 131072
empty_bucket_count = 0
avg_chain_len = 873
max_chain_length = 1009

버킷 수를 변경하여 sys.dm_db_xtp_hash_index_stats 의 출력 은 다음과 같습니다.

total_bucket_count = 134217728
empty_bucket_count = 131664087
avg_chain_len = 1
max_chain_length = 3

그럼에도 불구하고 결과는 더 나쁘지 않더라도 거의 같습니다.


매개 변수 스니핑이 발생하지 않습니까? OPTION(OPTIMIZE FOR UNKNOWN)( 테이블 힌트 참조)로 쿼리를 실행 해 보셨습니까 ?
TT.

내 생각에 행 체인 문제가 발생했습니다. 당신은 우리에게 출력을 줄 수 있습니까 select * from sys.dm_db_xtp_hash_index_stats ? 또한이 링크는 대부분 / 모든 질문에 답변해야합니다. msdn.microsoft.com/en-us/library/…
Sean Gallardy

4
해시 인덱스는 포함 된 두 열의 조건 자에만 유용합니다. 테이블에 해시 인덱스없이 시도 했습니까?
Mikael Eriksson

인 메모리 기술을 통한 최상의 성능 향상은 기본적으로 컴파일 된 저장 프로 시저 를 통해서만 달성 할 수 있음을 발견했습니다 .
Daniel Hutmacher 2016 년

@DanielHutmacher FWIW 나는 모든 이점이 래칭을 제거하고 기본적으로 컴파일 된 프로 시저를 추가하여 얻을 수있는 반례를 보았지만 거의 개선되지 않았습니다. 나는 담요 진술에 대한 여지가 없다고 생각합니다 (이 경우에는 옳을 수도 있지만 세부 사항을 보지조차 못했습니다).
Aaron Bertrand

답변:


7

이 게시물은 정보가 부족하여 완전한 답변이되지는 않지만 올바른 방향으로 안내하거나 나중에 커뮤니티와 공유 할 수있는 통찰력을 얻을 수 있어야합니다.

불행히도,이 정의는 디스크 기반 테이블의 이전 상황과 관련하여 성능이 저하됩니다. 크기 차수는 10 % 정도 더 높거나 적습니다 (일부 경우 100 %에 도달하므로 더블 타임).

무엇보다도 Microsoft가 광고하는 잠금없는 아키텍처를 고려할 때 동시성 시나리오에서 뛰어난 이점을 얻을 것으로 기대했습니다. 대신 최악의 성능은 테이블에서 여러 쿼리를 실행하는 여러 명의 동시 사용자가있을 때입니다.

그것은 사실이어서는 안되므로 문제가됩니다. 특정 워크로드는 메모리 테이블에 포함되지 않으며 (SQL 2014) 일부 워크로드는 그에 적합합니다. 대부분의 상황에서 적절한 인덱스를 마이그레이션하고 선택하는 것만으로도 성능이 저하 될 수 있습니다.

원래 나는 이것에 관한 당신의 질문에 대해 매우 좁은 생각을하고있었습니다.

질문 :

  • 올바른 BUCKET_COUNT는 무엇입니까?
  • 어떤 종류의 색인을 사용해야합니까?
  • 디스크 기반 테이블보다 성능이 떨어지는 이유는 무엇입니까?

처음에는 실제 메모리 테이블과 인덱스가 최적이 아닌 문제가 있다고 생각했습니다. 메모리 최적화 해시 인덱스 정의에 몇 가지 문제가 있지만 실제 문제는 사용 된 쿼리와 관련이 있다고 생각합니다.

-- INSERT (can vary from 10s to 10,000s of records):
INSERT INTO MyTable
  SELECT @fixedValue, id2, col1, col2 FROM AnotherTable

이 삽입은 메모리 테이블에만 관련되어 있으면 매우 빠릅니다. 그러나 디스크 기반 테이블도 포함되며 이와 관련된 모든 잠금 및 차단이 적용됩니다. 따라서 실시간 낭비는 디스크 기반 테이블에 있습니다.

데이터를 메모리에로드 한 후 디스크 기반 테이블에서 100,000 행 삽입에 대해 빠른 테스트를 수행했을 때 1 초 미만의 응답 시간이었습니다. 그러나 대부분의 데이터는 20 초 미만의 매우 짧은 시간 동안 만 유지됩니다. 이것은 실제로 캐시에 살 시간이 충분하지 않습니다. 또한 나는 AnotherTable실제로 얼마나 큰지 확신 하지 못하며 값을 디스크에서 읽을 지 여부를 모릅니다. 우리는이 답변에 당신을 의지해야합니다.

선택 쿼리를 사용하여 :

SELECT id2, col1
FROM MyTable INNER JOIN OtherTbl ON MyTable.id2 = OtherTbl.pk
WHERE id1 = @value
ORDER BY col1

다시, 우리는 interop + 디스크 기반 테이블 성능의 자비에 있습니다. 또한 정렬은 HASH 인덱스에서 저렴하지 않으며 클러스터되지 않은 인덱스를 사용해야합니다. 이것은 의견에 링크 된 색인 안내서 에서 언급됩니다.

실제 연구 기반 사실을 제공하기 위해 실제 크기 또는 통계를 알지 못했기 때문에 SearchItems메모리 테이블에 천만 개의 행과 AnotherTable100,000 개의 행을 로드 했습니다. 그런 다음 위의 select 쿼리를 사용하여 실행했습니다. 또한 wait_completed에서 확장 이벤트 세션을 작성하여 링 버퍼에 넣었습니다. 각 실행 후 청소되었습니다. 또한 모든 데이터가 메모리 상주가 아닌 DBCC DROPCLEANBUFFERS환경을 시뮬레이션하기 위해 실행 했습니다 .

진공 상태에서 볼 때 그 결과는 훌륭하지 않았습니다. 내가 테스트하는 랩톱은 고급 SSD를 사용하고 있기 때문에 사용중인 VM의 디스크 기반 성능을 인위적으로 낮추었습니다.

인 메모리 기반 테이블에서 쿼리를 5 회 실행 한 후 (조인은 제거하고 하위 쿼리는 제거하지 않은 후) 대기 정보없이 결과가 나타납니다. 이것은 예상대로입니다.

그러나 원래 쿼리를 사용할 때 기다렸습니다. 이 경우 데이터가 디스크에서 읽히는 동안 의미가있는 PAGEIOLATCH_SH입니다. 이 시스템 의 유일한 사용자이며 조인 된 테이블에 대한 삽입, 업데이트, 삭제에 대한 대규모 테스트 환경을 만드는 데 시간을 소비하지 않았기 때문에 잠금 또는 차단이 적용되지 않을 것으로 예상했습니다.

이 경우 다시 한 번 많은 시간이 디스크 기반 테이블에서 소비되었습니다.

마지막으로 삭제 쿼리입니다. ID1만으로 행을 찾는 것은 has 인덱스에서 매우 효율적이지 않습니다. 항등 술어가 해시 인덱스에 적합한 것은 사실이지만 데이터가 포함되는 버킷은 전체 해시 열을 기반으로합니다. 따라서 id1, id2, id1 = 1, id2 = 2 및 id1 = 1, id2 = 3은 해시가 (1,2) 및 (1,3)을 가로 질러 서로 다른 버킷으로 해시됩니다. 해시 인덱스는 같은 방식으로 구성되지 않기 때문에 간단한 B- 트리 범위 스캔이 아닙니다. 그런 다음 이 작업에 이상적인 인덱스가 아닐 것으로 예상하지만 경험보다 더 오래 걸릴 것으로 예상하지는 않습니다. 이것에 대해 wait_info를 보는 데 관심이 있습니다.

무엇보다도 Microsoft가 광고하는 잠금없는 아키텍처를 고려할 때 동시성 시나리오에서 뛰어난 이점을 얻을 것으로 기대했습니다. 대신 최악의 성능은 테이블에서 여러 쿼리를 실행하는 여러 명의 동시 사용자가있을 때입니다.

잠금이 논리적 일관성을 위해 사용되는 것은 사실이지만, 작업은 여전히 ​​원자 적이어야합니다. 이는 특수 CPU 기반 비교 연산자를 통해 수행됩니다 (따라서 In-Memory는 특정 (최근 4 년 동안 작성된 거의 모든 CPU) 프로세서에서만 작동합니다). 따라서 우리는 모든 것을 무료로 얻지 못하지만 이러한 작업을 완료하는 데 여전히 시간이 있습니다.

제기해야 할 또 다른 요점은 거의 모든 쿼리에서 사용 된 인터페이스가 T-SQL (기본적으로 컴파일 된 SPROC가 아님)이며, 이는 적어도 하나의 디스크 기반 테이블을 모두 처리한다는 것입니다. 이것이 결국 디스크 기반 테이블의 성능에 제약을 받으므로 실제로 성능이 향상되지 않는다고 생각하는 이유입니다.

후속 조치 :

  1. wait_completed에 대한 확장 이벤트 세션을 작성하고 알려진 SPID를 지정하십시오. 쿼리를 실행하고 출력을 제공하거나 내부적으로 소비하십시오.

  2. # 1의 출력에 대한 업데이트를 제공하십시오.

  3. 해시 인덱스의 버킷 수를 결정하기위한 마법 번호는 없습니다. 기본적으로 버킷이 완전히 채워지지 않고 행 체인이 3 또는 4 아래로 유지되는 한 성능은 수용 가능해야합니다. "로그 파일을 무엇으로 설정해야합니까?" -프로세스, 데이터베이스, 사용 유형에 따라 다릅니다.

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