MySQL : 14 억 레코드에 대한 인덱스 생성


9

14 억 개의 레코드가있는 테이블이 있습니다. 테이블 구조는 다음과 같습니다.

CREATE TABLE text_page (
    text VARCHAR(255),
    page_id INT UNSIGNED
) ENGINE=MYISAM DEFAULT CHARSET=ascii

열에 대한 색인을 작성해야합니다 text.

테이블 크기는 약 34G입니다.

다음 문장으로 색인을 만들려고했습니다.

ALTER TABLE text_page ADD KEY ix_text (text)

10 시간을 기다린 후에 마침내이 접근법을 포기했습니다.

이 문제에 대한 해결책이 있습니까?

UPDATE : 테이블을 업데이트하거나 삽입하거나 삭제할 수 없습니다. 컬럼에서 인덱스를 작성하는 이유 text는 다음과 같은 종류의 SQL 쿼리가 자주 실행되기 때문입니다.

SELECT page_id FROM text_page WHERE text = ?

업데이트 : 테이블을 분할하여 문제를 해결했습니다.

테이블은 열에서 40 개로 분할됩니다 text. 그런 다음 테이블에서 인덱스 작성을 완료하는 데 약 1 시간이 걸립니다.

테이블 크기가 매우 커지면 MySQL 인덱스 생성이 매우 느려집니다. 그리고 파티셔닝은 테이블을 더 작은 트렁크로 줄입니다.


1
일반적인 CREATE INDEX진술 을 사용하는 데 무엇이 문제입니까 ?

이 질문은 ServerFault에서 더 나을 수 있다고 제안합니다. 프로그래밍 질문보다 DB 관리자에 가깝습니다.
therefromhere

@Derk : 일반적인 CREATE INDEX 접근 방식이 너무 느립니다. 하루 안에 작업을 완료해야합니다.

1
흠 ... 나는 당신 이이 문제를 해결할 수 있다고 생각하지 않습니다. 인덱스를 빌드하려면 DBMS가 모든 레코드를 스캔하고 "텍스트"필드를 수집하고 해당 트리 노드 / 하위 트리를 삽입 / 변경해야합니다. 그리고 이것은 ... (34G)에 많은 시간을 소요
chiccodoro

DB 서버의 메모리 용량은 얼마입니까? 모든 메모리를 사용하도록 MySQL을 구성 했습니까, 아니면 스스로 제한합니까?

답변:


4

시스템이 작업에 달려 있지 않을 수 있습니까? MySQL (여기서는 SQL Server)을 사용하지 않지만 8 억 개의 엔트리 테이블을 인덱싱해야하는 어려움을 알고 있습니다. 기본적으로 .... 많은 빠른 디스크와 같이 적절한 하드웨어가 필요합니다. 나는 이제 거의 12 개의 Velociraptor를 사용하고 성능은 훌륭합니다.)

SQL Server (MS SQL Server가 아니라 SQL을 사용하는 데이터베이스 서버)는 디스크 액세스로 라이브 및 다이를 사용하며 일반 디스크는 더 큰 작업을 수행하지 않습니다.


필자의 의심은 레코드 수가 적 으면 색인 작성이 일반적으로 매우 빠르다는 것입니다. 수백만이라고 말해 그러나 카운트가 수십억에 달하면 인덱스 생성이 너무 느려집니다. 시간이 기하 급수적으로 증가하는 것 같습니다.

실제로는 안됩니다. 일반적으로 MySQL에는 한계가 있지만 쓰레기 데이터베이스가 아니며 매우 나쁩니다. 인덱스 생성 속도가 느려지지만 (n)이 아닌 log (n)에 의해 실제로 그렇게 나쁘지 않아야합니다.
TomTom

4

텍스트 필드의 첫 번째 (예 : 10) 문자에 대한 인덱스를 만들 수 있습니다.

문서에서 :

col_name (length) 구문을 사용하여 인덱스 접두사 길이를 지정하여 열 값의 앞 부분 만 사용하는 인덱스를 만들 수 있습니다.

CREATE INDEX ix_text ON text_page (text(10))

4

테이블을 분할하여 문제를 해결했습니다.

테이블은 열에서 40 개로 분할됩니다 text. 그런 다음 테이블에서 인덱스 작성을 완료하는 데 약 1 시간이 걸립니다.

테이블 크기가 매우 커지면 MySQL 인덱스 생성이 매우 느려집니다. 그리고 파티셔닝은 테이블을 더 작은 트렁크로 줄입니다.


40 x 1 시간이 10 시간 미만입니까?
symcbean

3

sort_buffer_size를 4GB로 설정하십시오 (또는 보유하고있는 메모리 용량에 따라 많이 할 수 있습니다).

지금 create 인덱스는 정렬을 수행하지만 32MB sort_buffer_size가 있으므로 기본적으로 하드 드라이브를 불필요하게 스 래싱합니다.


이 게시물은 xaprb.com/blog/2010/05/09/how-to-tune-mysqls-sort_buffer_size 및 더 나은 ronaldbradford.com/blog/ 와 거의 일치하지 않습니다. 세계적인 가치는 아닌 것 같습니다. 쿼리 당으로 권장되는 쿼리 당 4GB입니다. 또한 256K를 초과하면 실제 메모리 내 메모리가 아닌 디스크에 메모리 매핑됩니다. 작게 유지하면 여러 번의 패스가 필요하지만 디스크를 피할 수 있습니다 (스왑하지 않음).
Ry4an Brase

3

다음과 같이 쿼리 할 필요가없는 경우 :

SELECT page_id FROM text_page WHERE text LIKE '?%';

새 해시 열을 만들고 열을 기준으로 테이블을 인덱싱하는 것이 좋습니다. 테이블 + 인덱스의 전체 크기는 훨씬 작을 수 있습니다.

UPD : 그런데 14 억 개의 1 차 키 정수는 약 6GB를 차지합니다. 즉, 문자열의 평균 길이는 30 자 미만입니다.

MERGE 스토리지 엔진도 살펴 봐야 합니다.


2

이를 수행하는 한 가지 방법은 인덱스 세트로 새 테이블을 작성하고 데이터를 새 테이블에 복사하는 것입니다.

또한 충분한 임시 공간이 있는지 확인하십시오.


1
나는이 접근법을 시도했다. 10 시간 후 1 % 미만의 데이터가 새 테이블로 복사되었습니다.

1
야 .. 1.4 억 기록이야. 백만이 아닙니다. 많이입니다. 상관없이 시간이 걸릴 것입니다.

이 방법을 선택하면 사본을 더 작은 청크로 나눕니다. 각 사본마다 약 1 억에서 2 억 정도를 말합니다.

1
@decompiled, 작은 덩어리로 나누면 아무것도하지 않습니다 (실제로 효율이 떨어질 수 있습니다). @Bryan, 14 억 건의 기록이 있어도 1,000 시간이 걸리지 않습니다.

0

여전히 최선을 다하는 방법이 궁금하다면 온라인 alter table 도구를 사용하는 것이 좋습니다.

인터넷에는 많은 것들이 있으며 유명한 것들 중 하나는 다음과 같습니다.

우리는 큰 테이블 (500mil 이상의 레코드)과 동일한 문제가 있으며 변경이 완벽합니다. 새 tmp 테이블을 작성하고, 원래 테이블에 트리거를 추가하고 (새 업데이트 / 삭제 / 삽입 레코드에 대해) 그 동안 모든 레코드를 새 테이블에 새 구조로 복사합니다.

행운을 빕니다!

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