2011-09-25 22 views
5

~ 1 milyon satır içeren bir InnoDB MySql Geo ID tablom var. Tablo yapısını şudur:Tek bir Sorgu için bu MySQL tablomun daha da iyileştirilmesi

CREATE TABLE `geoid` (
    `start_ip` int(11) NOT NULL, 
    `end_ip` int(11) NOT NULL, 
    `city` varchar(64) NOT NULL, 
    `region` char(2) NOT NULL, 
    PRIMARY KEY (`start_ip`,`end_ip`) 
) ENGINE=InnoDB DEFAULT CHARSET=latin1; 

Sadece bir tip sorgu bu tabloya karşı ran olacaktır:

SELECT city, region FROM geoid WHERE 1259650516 BETWEEN start_ip AND end_ip 

Bu sorgu yaklaşık ~ 0,4228 sn sürer, süper yavaş ama inanılmaz derecede hızlı değil değil eter.

Soruma soru: Tabloyu bu tek sorgu için nasıl daha da optimize edebilirim?

Aşağıdaki şeyler denedim:

  1. Değişim MyISAM için Depolama Motoru, bu sorgu yaklaşık 1.9 sn almak yaptı.
  2. WHERE ifadesini kullanın 'WHERE geoid.start_ip < = 1259650516 VE 1259650516 < = geoid.end_ip'. Ama bu .4 ish yerine yürütmek için yaklaşık 5 saniye sürer.

Daha az yapmak için tüm gereksiz satırları tablodan kaldırdım. 1 milyonun hepsine ihtiyacım var. Aşağıdaki yazıya

GÜNCELLEME/ÇÖZÜM

sayesinde burada ben bu sorunu çözmek için bunu yaptı.

Yukarıdaki tabloya yeni bir sütun eklendi (sadece başka ilgilenen herkes için bu cevabı tamamlamak için): Sonra start_ip coğrafi verileri ile yeni bir sütun dolu

ALTER TABLE `geoid` ADD `geoip` LINESTRING NOT NULL 

ve end_ip

GeomFromText(CONCAT('LINESTRING(', start_ip, ' -1, ', end_ip, ' 1)')) 

sonra hepsi Oradan

CREATE SPATIAL INDEX geoip_index ON geoid(geoip); 

yeni sütun üzerinde kayma dizin yarattı

SELECT city, region FROM geoid WHERE MBRContains(geoip, GeomFromText(CONCAT('POINT(', 1259650516, ' 0)'))); 

VE YAPILDI: Eğer sorgunuzu değiştirecek mi yapmak zorundayız. Bu sorguyu .42 sn'den .0003 sn'ye düşürdü !!!!!!!

Bu INDEX'i seviyorum. Teşekkür ederim. Umarım yardımcı olur.

+0

Bir 'InnoDB' tablosunda bir 'SPATIAL' indeksi oluşturdunuz? – Quassnoi

+0

İlk önce MyISAM'a dönüştürdüm. – RonSper

cevap

3

end_ip numaralı dizine bir dizin eklemeye çalışın. Bu, bazı durumlarda sorguyu iki kat daha hızlı yapmalıdır.

Daha iyi bir performans için this article'da açıklandığı gibi bir SPATIAL endeksi kullanmanız gerekir.

+1

Birinciye ek olarak mı? Gibi: PRIMARY KEY ('start_ip',' end_ip'), ANAHTAR start_ip' ('start_ip'), KEY' end_ip' ('end_ip'). Bu hiçbir şeyi değiştirmedi. – RonSper

+0

@Ron Sper: Sorguyu her durumda hızlandırmaz ve yalnızca diğer durumlarda nispeten küçük bir hız sağlar. Daha iyi bir performans istiyorsanız, bir SPATIAL endeksi düşünebilirsiniz. Bu makaleye bakın: http://explainextended.com/2009/09/29/adjacency-list-vs-nested-sets-mysql/. Ama yeni başlayanlar için değil. –

+1

WOW, bu mükemmel. Tam istediğim bu. Teşekkür ederim. – RonSper

0

Sorguya dahil olan tüm alanlarda dizin oluşturmaya çalışın. Bu özel durumda iki alan üzerinde bir dizin oluştur (start_ip ve end_ip)