2012-02-02 4 views
9

최근에 내 프로젝트 테이블을 InnoDB로 전환했습니다 (관계가 좋은 것으로 생각합니다). 한 번에 약 500 개의 제품 색인을 생성하는 PHP 스크립트를 사용하고 있습니다.InnoDB가 매우 천천히 삽입하고 속도가 느려짐

테이블 저장 단어/IDS 협회 :

CREATE TABLE `windex` (
`word` varchar(64) NOT NULL, 
`wid` int(10) unsigned NOT NULL AUTO_INCREMENT, 
`count` int(11) unsigned NOT NULL DEFAULT '1', 
PRIMARY KEY (`wid`), 
UNIQUE KEY `word` (`word`) 
) ENGINE=InnoDB AUTO_INCREMENT=324551 DEFAULT CHARSET=latin1 

또 다른 테이블에는 제품 ID/워드 아이디 협회 :

CREATE TABLE `indx_0` (
`wid` int(7) unsigned NOT NULL, 
`pid` int(7) unsigned NOT NULL, 
UNIQUE KEY `wid` (`wid`,`pid`), 
KEY `pid` (`pid`), 
CONSTRAINT `indx_0_ibfk_1` FOREIGN KEY (`wid`) REFERENCES `windex` (`wid`) ON DELETE CASCADE ON UPDATE CASCADE, 
CONSTRAINT `indx_0_ibfk_2` FOREIGN KEY (`pid`) REFERENCES `product` (`ID`) ON DELETE CASCADE ON UPDATE CASCADE 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 

스크립트가의 MyISAM을 사용하여 테스트 한과 인덱스 제품 상대적으로 빠른 (많이 , InnoDB보다 훨씬 빠름). InnoDB에서 처음 실행하는 것은 엄청나게 느리지 만, 더 많은 값을 중첩시킨 후에는 충분히 빨라지게되었습니다 (그러나 충분하지는 않습니다).

나는 innodb가 로우 레벨 잠금 때문에이 유형의 것이 훨씬 빠르다고 생각 하겠지만, 그렇지 않다.

SELECT 
title,keywords,upc,... 
FROM product 
WHERE indexed = 0 
LIMIT 500 

내가 루프를 만들고 유리창 세제에 추가하고 필요한 모든 단어 ID/제품 ID 쌍해야 할 모든 단어 배열을 채우기 :

내가 좋아하는 뭔가를 보이는 쿼리를 생성 indx_0에 추가됩니다.

중복 값으로 인해 실패한 "REPLACE INTO"또는 "INSERT IGNORE INTO"를 수행 할 때마다 innodb가 자동 증가 값을 계속 유지하므로 추가 할 값이 없는지 확인해야합니다. 내가 처음과 같은 같은 쿼리를 사용하여 존재하는 모든 값을 선택하는 것이 수행합니다

SELECT wid,word 
FROM windex 
WHERE 
word = "someword1" or word = "someword2" or word = "someword3" ... ... 

그때 나는 100 % 새로운 추가하여 모든 새로운 단어를 존재하는 결과에 대해 내 배열을 필터링 할 수 있습니다.

전체 실행 시간의 약 20 %를 차지합니다. 나머지 80 %는 indx_0에 쌍 값을 더 추가합니다. 더 많은 값이 있습니다.

다음은 내가 얻은 것의 예입니다.

0.4806 초. (총 0.4807 초).
0.0319 초에 500 개의 항목을 수집합니다. (총 0.5126 초).
5.2396 초 비교를 위해 windex 값을 선택하십시오. (총 5.7836 초).
카운트를 업데이트하는 데 1.8986 초. (총 7.6822 초).
8 초 windex 레코드를 추가하는 데 0.0641 초. (총 7.7464 초).
17.2725 초에 3435 pid/wid 쌍의 색인을 추가합니다. (총 25.7752 초).
500 개 제품의 색인 생성 작업에 26.07 초가 걸렸습니다.

INSERT INTO indx_0(pid,wid) 
VALUES (1,4),(3,9),(9,2)... ... ... 

왜 InnoDB하지만 내 경우의 MyISAM보다 훨씬 느립니다 :

3천4백35쌍

모두 같은 하나의 쿼리에서 실행되고있다?

+0

검색 기능을 만들기 위해 색인이라는 단어 아이디어가 있습니까? 그렇다면 solr 나 mysql fulltext 검색과 같은 실제 검색 엔진을 살펴보십시오. 이러한 특정 작업을 능가 할 수는 없습니다. –

답변

13

InnoDB는 MyIsam (FOREIGN KEYS)보다 복잡한 키 구조를 제공하며 InnoDB에서 재생성 키가 실제로 느립니다.하나의 트랜잭션에 모든 업데이트/삽입 문을 동봉해야합니다 (두 개의 인덱스가있는 InnoDb 테이블에 약 300,000 개의 삽입 쿼리가 있고 약 10,000 분의 인서 트를 매번 BEGIN TRANSACTION에 넣으면 실제로 상당히 빠릅니다) 그리고 COMMIT 그것은 2 분 미만 걸렸다).

내가 사용하는 것이 좋습니다 :

BEGIN TRANSACTION; 
SELECT ... FROM products; 
UPDATE ...; 
INSERT INTO ...; 
INSERT INTO ...; 
INSERT INTO ...; 
COMMIT; 

은 InnoDB에 한 번만 백하지 몇 번 인덱스를 갱신하게됩니다. 그것이 내가 비슷한 문제가 있었다 기본에서 innodb_flush_log_at_trx_commit이 하드 디스크의 로그 파일에있는 모든 삽입/업데이트 쿼리를 플러시하는 활성화에 의해 InnoDB하지만 것 같다

+0

확실히 믿을만한 개선이 있어야합니다. 비슷한 문제가 있습니다. 이것이 효과가있는 것 같습니다. 감사합니다 - 우와 – Uday

+2

커서가 90 초에서 0.9 초로 고정 된 문제가 있습니다. 천천히 나는 InnoDB가 요구하는 것을 배우고 있습니다. –

+0

@Vyktor, * "나는 10 000 개의 인서트를 모두 BEGIN TRANSACTION으로 묶었습니다. 'COMMIT'는 2 분이 채 걸리지 않았습니다. *, 왜 10k 배치로 나눕니까? ** 모든 ** 명세서를 하나의 단일 거래로 묶지 않는 이유는 무엇입니까? – Pacerier

4

을 일했다면

은 알려주세요. 하드 디스크의 쓰기 속도가이 프로세스의 병목입니다.

그래서 MySQL의 설정 파일을

`innodb_flush_log_at_trx_commit = 0` 

다시 시작 MySQL의 서비스를 수정하려고합니다.

삽입물의 속도가 약 100 배 빨라졌습니다.

+1

비록이 옵션을 적용해도 트랜잭션 안전성이 상실된다는 사실을 알고 있어야합니다 ... 클라이언트에게 말한 후에 전원이 꺼지더라도 실제로 디스크에 쓰여지기 전에 영원히 손실됩니다. – Cine

관련 문제