2012-02-02 19 views
9

Yakın zamanda proje tablolarımı InnoDB'ye geçirdim (ilişkileri düşünmenin iyi bir şey olacağını düşünüyorum). Bir seferde 500 ürün endekslemek için bir PHP betiği kullanıyorum.InnoDB, çok yavaş ve yavaşlama ekler

bir tablo depolama kelime/kimlikleri ilişki:

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 

başka bir tablo depolar ürün id/kelime kimliği birlikleri:

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 

komut MyISAM kullanılarak test edilmiş ve gösterge ürünler nispeten hızlı (çok InnoDB'den çok daha hızlı. InnoDB'de ilk kez koşmak gülünç bir şekilde yavaştı ama daha fazla değer bir araya getirildikten sonra çok fazla hızlandı (ama yeterli değil).

Bu tür şeyler için innodb'lerin daha hızlı olacağı farzedilirdi, çünkü bu tip bir şey, siperli kilitlerdi, ancak durum böyle değil.

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

Ben bir döngü oluşturmak ve windex eklendi ve gereken tüm kelime kimliği/ürün kimliği çiftleri gereken tüm kelimelerle dizisi doldurun:

Ben şuna benzer bir sorgu oluşturmak indx_0'a eklenecek.

Yinelenen değerler nedeniyle başarısız olan bir "INTO INTO" veya "INSERT IGNORE INTO" yaptığımda innodb otomatik artış değerlerimi artırmaya devam ettiğinden, eklediğim değerlerin zaten mevcut olmadığından emin olmam gerekiyor. Ben bu tür ilk gibi bir sorgu kullanarak bulunmamakta tüm değerleri seçmek Bunu yapmak için:

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

O zaman% 100 yeni ekleme tüm yeni kelimeleri mevcut sonuçların karşı benim dizi filtre.

Bu, toplam yürütme süresinin yaklaşık% 20'sini alır. Diğer% 80, daha fazla değer bulunan çift değerlerini indx_0 içine eklemeye gider.

İşte elde ettiğim bir örnek. Ürünleri seçmek için

0.4806 saniye. (Toplam 0.4807 sn).
500 ürün toplamak için 0.0319 saniye. (Toplam 0.5126 sn). Karşılaştırma için windex değerlerini seçmek için
5.2396 saniye. (Toplam 5.7836 sn). Sayısı güncelleştirmek için 08986 saniye. (Toplam 7.6822 sn). 832 windex kayıtlarını eklemek için
0.0641 saniye. (Toplam 7.7464 sn).
3435 pid/wid çiftlerinin indeksini eklemek için 17.2725 saniye. (Toplam 25.7752 sn).
Operasyon, 500 ürünü endekslemek için 26.07 saniyeyi aldı.

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

Neden InnoDB'nin benim durumumda MyISAM çok daha yavaştır:

3435 çiftleri

tüm bu haliyle tek sorguda yürütülmektedir?

+0

Bir tür arama işlevi oluşturmak için kelime dizini fikri nedir? Böyle bir durum söz konusuysa, örneğin, solr veya mysql tam metin araması gibi gerçek bir arama motoruna göz atın. Bu gibi belirli görevlerden üstün olamaz. –

cevap

13

InnoDB, MyIsam'dan (FOREIGN KEYS) daha karmaşık anahtar yapısı sağlar ve InnoDB'de yeniden oluşturma anahtarları gerçekten yavaştır.Tüm update/insert ifadelerini tek bir işlemde içine almalısınız (InnoDB'de oldukça hızlıdırlar), InnoDb tablosunda 2 indeksle yaklaşık 300 000 sorgulama yaptıktan sonra, her 10 000 eklentiyi BEGIN TRANSACTION'a ekledikten sonra yaklaşık 30 dakika sürdüm. ve COMMIT, 2 dakikadan daha az sürdü).

Ben kullanmanızı öneririz:

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

Bu

InnoDB'nin sadece bir kez yüz değil birkaç kez endeksleri yenilemek için neden olacaktır. ben benzer bir sorun vardı ve varsayılan innodb_flush_log_at_trx_commit sizin hdd günlük dosyası üzerinde her ekleme/güncelleme sorgusu temizler hangi etkin tarafından InnoDB'nin var gibi görünüyor

+0

Emin olduğuna inanıyorum ki, bir miktar gelişme sağlamalı. Benzer bir problemim var Vyktor. Bu işe yarayacak gibi görünüyor. Teşekkürler -günlük – Uday

+2

Bir imleçte bu sorunu çözdüm (90 saniyeden 0.9'a!) Yavaş yavaş InnoDB –

+0

@Vyktor'dan neyin gerekli olduğunu öğreniyorum, "* BEGIN TRANSACTION" içine her 10 000 eki ekledim ve 'COMMIT' 2 dakikadan az sürdü. *, Neden 10k'lık gruplara ayrılıyorsunuz? Neden tüm ** ifadeleri tek bir işlem içinde kapılmıyorsunuz? – Pacerier

4

yaradıysa

bana bildirin. Sabit diskinizin yazma hızı bu işlem için bir darboğazdır.

Yani MySQL yapılandırma dosyasını

`innodb_flush_log_at_trx_commit = 0` 

Yeniden MySQL hizmet değiştirmek için deneyin.

Eklentilerdeki x100 hızını deneyimledim.

+1

İşlem güvenliğinin bu seçeneği uygulayarak kaybolduğunun bilincinde olun ... Eğer istemciye söyledikten sonra gücü kaybederseniz, ancak gerçekten diske yazılmadan önce sonsuza dek kaybolduğu anlamına gelir. – Cine