1 (edited by Ramex 2010-05-21 15:59:00)

Topic: Reikia pagalbos optimizuojant užklausą su JOIN struktūra

bėda labai paprasta: turiu ganėtinai paprastą užklausą, tačiau ji vykdoma pernelyg ilgai. pirmiausia pradėsiu nuo lentelių.
Pagrindinė lentelė (36 515 įrašų):

CREATE TABLE IF NOT EXISTS `cms_module_aaproducts_products` (
  `id` int(11) NOT NULL,
  `nr` varchar(40) collate utf8_unicode_ci NOT NULL,
  `name` varchar(200) collate utf8_unicode_ci NOT NULL,
  `vnt` varchar(10) collate utf8_unicode_ci NOT NULL,
  `category` varchar(200) collate utf8_unicode_ci default NULL,
  `acode` varchar(40) collate utf8_unicode_ci NOT NULL,
  `orignr` varchar(40) collate utf8_unicode_ci default NULL,
  `price` float default NULL,
  `stock` float NOT NULL default '0',
  `brand` varchar(100) collate utf8_unicode_ci default NULL,
  PRIMARY KEY  (`id`),
  KEY `nr` (`nr`),
  KEY `orignr` (`orignr`),
  KEY `acode` (`acode`),
  KEY `name` (`name`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

šalutinė lentelė (242 658 įrašų):

CREATE TABLE IF NOT EXISTS `cms_module_aaproducts_brands` (
  `nr` varchar(25) collate utf8_unicode_ci NOT NULL,
  `brand` varchar(20) collate utf8_unicode_ci NOT NULL,
  `acode` varchar(40) collate utf8_unicode_ci NOT NULL,
  `search` varchar(255) collate utf8_unicode_ci default NULL,
  `modified` datetime NOT NULL,
  `created` datetime NOT NULL,
  KEY `nr` (`nr`),
  KEY `acode` (`acode`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

Pati užklausa:

SELECT t.* 
FROM cms_module_aaproducts_products t 
LEFT JOIN cms_module_aaproducts_brands b 
    ON b.acode=t.acode 
WHERE (t.name LIKE '%VKM13132%' 
    OR t.acode LIKE '%VKM13132%' 
    OR b.nr LIKE '%VKM13132%') 
    AND t.stock>0 
ORDER BY t.name ASC 
LIMIT 10

Explain gražina tokią informaciją (deja, bet man tai nieko nesako):

id     select_type     table     type     possible_keys     key     key_len     ref     rows     Extra 
1    SIMPLE    t    index    NULL    name    767    NULL    36515    Using where
1    SIMPLE    b    ref    acode    acode    122    kainynas_autoai.t.acode    18    Using where

Ar matote čias kažkokių netikslumų, kurie galėtu būti lėto užklausos vykdymo priežąstis. Užklausa įvydoma per 7s.

Su sąlyga, kad šūdo nebus...

Re: Reikia pagalbos optimizuojant užklausą su JOIN struktūra

Problemos yra dvi:
1) neteisingai sudėlioti raktai/indeksai; Aš nesuprantu ar šiais laikais jie nemadingi ir apie juos niekas nieko neskaito ar kame problemos? (-; Tavo atveju naudpjamas vienintelis indeksas: t.acode, nors reikėtų šiek tiek daugiau.
2) dar didesnė problema yra ta, kad tu tris stulpelius skanuoji su LIKE '%...%'; šitas dalykas ieško teksto fragmento trijuose stulpeliuose. Pvz lentelės "t" atveju skanuojami (36k * 2) įrašai.

Su LIKE '%...%' yra tokia situacija, kad turint normalią įrangą ir viską suderinus, kad skanuojamų duomenų kiekis būtų kuo mažesnis dar galima tilpti į protingas ribas. Jeigu duomenų daug tai šitas variantas netinka, reikia ieškoti kitų metodų. Geriausia atsisakyti tekstinio fragmento paieškos tarp didelių duomenų kiekių. Jeigu neišeina - remtis specializuotais produktais, pvz.: Sphinx'u.

3 (edited by Ramex 2010-05-21 17:07:50)

Re: Reikia pagalbos optimizuojant užklausą su JOIN struktūra

1) savo atveju aš nematau, kur galėčiau panaudot tuos raktus kaip tik lentelių susiejimui, nes mano atveju viso labo atliekama paieška tarp dviejų lentelių.
2) LIKE naudojami dėl to, kad reikia surasti tokią informaciją, kuri įvedamo kodo fragmentą (raidžių ir skaičių kratinį) gali turėti 3 skirtinguose laukuose (šiuo atveju 2 laukai vienoje lentelėje ir vienas kitoje). kodo fragmentas paieškomas visose lauko vietose (pradžia, galas, vidurys ar net visas laukas)

Su sąlyga, kad šūdo nebus...

Re: Reikia pagalbos optimizuojant užklausą su JOIN struktūra

Ramex wrote:

1) savo atveju aš nematau, kur galėčiau panaudot tuos raktus kaip tik lentelių susiejimui, nes mano atveju viso labo atliekama paieška tarp dviejų lentelių.

Jeigu akys manęs neapgauna pas tave be lentelių sujungimo yra dar ir WHERE bei ORDER operatoriai, kuriuose irgi naudojami tam tikri stulpeliai.

Be to, pas tave visi "indeksai" yra atskiri, kaip žinia MySQL'as naudoja tik vieną.

Ramex wrote:

2) LIKE naudojami dėl to, kad reikia surasti tokią informaciją, kuri įvedamo kodo fragmentą (raidžių ir skaičių kratinį) gali turėti 3 skirtinguose laukuose (šiuo atveju 2 laukai vienoje lentelėje ir vienas kitoje). kodo fragmentas paieškomas visose lauko vietose (pradžia, galas, vidurys ar net visas laukas)

Tai niekas nesikeičia - kaip ir sakiau - tokio tipo teksinės paieška galima tik tam tikrais atvejai, o plačiaja prasme reikia galvoti apie specializuotus sprendimu.

Beje, ten naudojai "EXPLAIN" ar "EXPLAIN EXTENDED"?

Re: Reikia pagalbos optimizuojant užklausą su JOIN struktūra

minde wrote:

Be to, pas tave visi "indeksai" yra atskiri, kaip žinia MySQL'as naudoja tik vieną.

Tai tu siūlai tuos indeksus, kuriuos naudoju, apjungti į vieną?

minde wrote:

Beje, ten naudojai "EXPLAIN" ar "EXPLAIN EXTENDED"?

Aš naudojau EXPLAIN, bet EXPLAIN EXTENDED grąžina tą patį.

Su sąlyga, kad šūdo nebus...

Re: Reikia pagalbos optimizuojant užklausą su JOIN struktūra

Ramex wrote:

Tai tu siūlai tuos indeksus, kuriuos naudoju, apjungti į vieną?

Na pirmiausia tai aš siūlau pasiskaityti dokumentacijoje, kaip veikia tie indeksai ir kaip juos naudoti.

Paskui siūlau susirinkti visas sistemoje naudojamas užklausas ir jas susisiteminti. Tada apie konkrečia lentelę gausi tam tikrą užklausų skaičių, kuriom visom pasinagrinėjęs vykdymo planus (execution plan / explainus) išsiaiškinti kokios indeksų grupės reikalingos.

Yra paprastas dalykas, kad MySQL'as vienoje užklausoje vienai lentelei naudoja vieną indeksą. Jeigu pas tave toje užklausoje yra bent 3 stulpeliai WHERE sąlygoje, tai akivaizdu, kad tik vienam iš tų trijų bus panaudotas indeksas, o kitiem dviem bus atliekami bereikalingi lentelės skanavimai. Tai čia šiaip, teoriškai, netaikant konkrečiai tavo atvejui.

Re: Reikia pagalbos optimizuojant užklausą su JOIN struktūra

na problemą pavyko dalinai praspręsti (nubraukiant beveik 6s) kombinuojant UNION ir JOIN kontrukcijas. aišku tai dar visai manęs netenkina, bet bent jau pakeičiama.
toliau manau ieškosiu sprendimo keičiant duomenų bazės struktūrą, kad galėčiau paiešką atlikti tarp indeksų, o ne tarp teksto eilučių.

Su sąlyga, kad šūdo nebus...