전체 텍스트 검색은 'FULLTEXT 초기화'에 많은 시간을 소비합니다


12

현재 Stack Overflow 주석의 데이터 덤프에 대해 일부 쿼리를 실행하려고합니다. 스키마는 다음과 같습니다.

CREATE TABLE `socomments` (
  `Id` int(11) NOT NULL,
  `PostId` int(11) NOT NULL,
  `Score` int(11) DEFAULT NULL,
  `Text` varchar(600) NOT NULL,
  `CreationDate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  `UserId` int(11) NOT NULL,
  PRIMARY KEY (`Id`),
  KEY `idx_socomments_PostId` (`PostId`),
  KEY `CreationDate` (`CreationDate`),
  FULLTEXT KEY `Text` (`Text`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

이 쿼리를 테이블에 대해 실행했으며 놀랍게도 느리게 실행되었습니다 (29 백만 행이 있지만 전체 텍스트 인덱스가 있음).

SELECT *
FROM socomments
WHERE MATCH (Text) AGAINST ('"fixed the post"' IN BOOLEAN MODE)

그래서 나는 그것을 프로파일 링했는데 그 결과는 다음과 같습니다.

|| Status                     || Duration ||
|| starting                   || 0.000058 ||
|| checking permissions       || 0.000006 ||
|| Opening tables             || 0.000014 ||
|| init                       || 0.000019 ||
|| System lock                || 0.000006 ||
|| optimizing                 || 0.000007 ||
|| statistics                 || 0.000013 ||
|| preparing                  || 0.000005 ||
|| FULLTEXT initialization    || 207.1112 ||
|| executing                  || 0.000009 ||
|| Sending data               || 0.000856 ||
|| end                        || 0.000004 ||
|| query end                  || 0.000004 ||
|| closing tables             || 0.000006 ||
|| freeing items              || 0.000059 ||
|| logging slow query         || 0.000037 ||
|| cleaning up                || 0.000046 ||

보시다시피, FULLTEXT 초기화에 오랜 시간이 걸립니다. 이것이 정상입니까? 그렇지 않은 경우 어떻게 해결합니까?


아이디어 : 하나의 텍스트 필드에 1.000 개의 설명을 넣을 두 번째 테이블을 만듭니다. 이제이 두 번째 테이블에서 처음 검색하면 예를 들어 id_group 2id_group 23. 이를 통해 기본 테이블 내에서 검색하고 쿼리 범위를 2.000 ~ 2.999 및 23.000 ~ 23.999의 ID 범위로 제한하십시오. 물론 두 번째 키워드는 모든 키워드를 조합하여 새로운 키워드 조합을 만들면 필요에 따라 더 많은 결과를 얻을 수 있지만 결국 전체 속도를 높여야합니다. 물론 디스크 공간 사용량이 두 배가됩니다. 새로운 코멘트한다 CONCAT'ed 그룹 테이블에.
mgutt

답변:


5

다른 사람들은 이것이 귀찮은 상황을 발견했습니다

MySQL 문서는이 스레드 상태에 대해 매우 간결 하므로

전체 텍스트 초기화

서버가 자연어 전체 텍스트 검색을 수행 할 준비를하고 있습니다.

유일한 해결책은 적은 데이터로 준비하는 것입니다. 어떻게 ?

제안 # 1

검색어를 다시 확인하십시오. 모든 열을 선택하고 있습니다. 에서 id 열만 수집하도록 쿼리를 리팩터링합니다 socomments. 그런 다음 검색된 ID를 socomments테이블에 다시 결합 하십시오.

SELECT B.* FROM
(SELECT id FROM socomments
WHERE MATCH (Text) AGAINST ('"fixed the post"' IN BOOLEAN MODE)) A
LEFT JOIN socomments B USING (id);

이것은 추한 EXPLAIN 계획을 생성 할 수 있지만 프로파일 링이 더 나아질 것이라고 생각합니다. 기본 아이디어는 다음과 같습니다. 공격적인 전체 텍스트 검색이있는 경우 해당 FULLTEXT initialization단계 에서 가장 적은 양의 데이터를 수집 하여 시간을 줄이십시오.

나는 전에 이것을 여러 번 추천했습니다

제안 # 2

MyISAM이 아닌 InnoDB 기반 FULLTEXT 옵션을 설정했는지 확인하십시오. 걱정해야 할 두 가지 옵션은 다음과 같습니다.

잠시 생각해보십시오. 텍스트 필드는 VARCHAR (600)입니다. 평균이 300 바이트라고 가정하십시오. 당신은 29,000,000 백만이 있습니다. 그것은 8GB 정도가 될 것입니다. 아마도 innodb_ft_cache_sizeinnodb_ft_total_cache_size를 늘리면 도움이 될 수 있습니다.

더 큰 InnoDB FULLTEXT 버퍼를위한 충분한 RAM이 있는지 확인하십시오.

시도 해봐 !!!


두 제안을 모두 시도한 결과 약 10 초에서 200 초로 시간이 단축되었습니다. 이상한 점은 버퍼 풀의 사용률이 9 %에 불과하다는 것입니다.
hichris123

AGAINST 부분에 더하기 부호를 넣어서 SELECT B.* FROM (SELECT id FROM socomments WHERE MATCH (Text) AGAINST ('+"fixed the post"' IN BOOLEAN MODE)) A LEFT JOIN socomments B USING (id);차이가 있는지 확인하십시오.
RolandoMySQLDBA

내가 더하기 기호를 제안한 이유는 무엇입니까? Doc ( dev.mysql.com/doc/refman/5.6/en/fulltext-boolean.html )은 A leading or trailing plus sign indicates that this word must be present in each row that is returned. InnoDB only supports leading plus signs.특정 경우 정확한 문구 fixed the post가 존재해야 한다고 말합니다 .
RolandoMySQLDBA

같은 결과입니다. 조금 더 빠르고 느리기 때문에 실행 시점의 미세한 차이 때문일 수 있습니다.
hichris123

5

InnoDB FULLTEXT 인덱스를 사용하는 경우 삭제 된 행 수가 많은 테이블에 대해 쿼리하는 경우 쿼리가 종종 "FULLTEXT 초기화"상태로 정지됩니다. InnoDB의 FULLTEXT 구현에서, 영향을받는 테이블에 대해 후속 OPTIMIZE 조작이 실행될 때까지 삭제 된 행이 제거되지 않습니다. 참조 : https://dev.mysql.com/doc/refman/5.6/en/innodb-fulltext-index.html

삭제 된 레코드에 대한 전체 텍스트 인덱스 항목을 제거하려면 innodb_optimize_fulltext_only = ON으로 인덱스 테이블에서 OPTIMIZE TABLE을 실행하여 전체 텍스트 인덱스를 다시 작성해야합니다.

information_schema.innodb_ft_deleted 를 질의하여 삭제되었지만 제거되지 않은 레코드 수를 검사 할 수도 있습니다.

이 문제를 해결하려면 InnoDB FULLTEXT 인덱스가있는 테이블에 대해 정기적으로 OPTIMIZE TABLE을 실행해야합니다.


나는이에 논리를 얻을 수 있지만, 당신은 확인할 수 innodb_optimize_fulltext_only=1OPTIMIZE테이블은 실제로 "대기의"삭제 된 행을 담당? dba.stackexchange.com/questions/174486/…
Riedsio


0

MySQL의 전체 텍스트 인덱스는 많은 양의 데이터를 지원하도록 설계되지 않았으므로 데이터 세트가 성장함에 따라 검색 속도가 매우 빠르게 떨어집니다. 솔루션 중 하나는 Solr 또는 Sphinx와 같은 외부 전체 텍스트 검색 엔진을 사용하여 검색 기능 (관련성 조정 및 구문 검색 지원, 내장 패싯, 스 니펫 등)이 확장 된 쿼리 구문을 제공하고 중간에서 훨씬 빠른 속도를 제공합니다. 큰 데이터 세트.

Solr은 Java 플랫폼을 기반으로하므로 Java 기반 응용 프로그램을 실행하면 자연스럽게 선택됩니다. Sphinx는 C ++로 작성되며 MySQL과 동일한 방식으로 데몬으로 작동합니다. 검색하려는 데이터를 외부 엔진에 공급하자마자 MySQL에서 일부 쿼리를 이동할 수도 있습니다. 나는 당신의 경우에 어떤 엔진이 더 낫다고 말할 수 없으며, 나는 대부분 스핑크스를 사용하며 여기에 사용 예제가 있습니다 : http://astellar.com/2011/12/replacing-mysql-full-text-search-with-sphinx/

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