Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: Dlugi czas wykonywania zapytania na rozbudowanej bazie
Forum PHP.pl > Forum > Bazy danych > MySQL
madar
Witam,
Opiszę problem:

tabela:
produkt
produkt2sklep (8mln)
sklep (40tys) (posiada pole id_sieci)
siec (200)

Gdy chcę pobrać produkty należące do danej sieci, robie (w uproszczeniu): product JOIN produkt2sklep JOIN sklep JOIN siec
(poniewaz sklep jest przypisany do sieci, a produkt do sklepu poprzez tabele produkt2sklep).

Poniewaz w ostatnim czasie bardzo rozrosła sie tabela produkt2sklep czas zapytan wzrósł do kilku sekund, a to stanowczo za duzo. Dodam, że używam indexów tam, gdzie potrzeba.

ROZWIAZANIE?
Czy dodac tabele product2siec, ktora bylaby uzywana tylko do tego zapytania? Chyba najwiekszym minusem tego rozwiazania jest utrata integralności, bo wtedy produkt jest przypisany do sieci poprzez bezposrednie polaczenie nową tabela, oraz przez stare polaczenie poprzez tabele sklep. Plusem natomiast jest to, ze biorac pod uwage ilosci wierszy w tabeli siec i produkt2sklep rozwiazanie to (wg mnie) znacznie skrociloby czas wykonywania zapytania.
Dla dbania o integralnosc pomyslalem, ze mozna codziennie uruchamiac skrypt, ktory bedzie aktualizowal tabele produkt2siec, zeby zawarte w niej dane byly zawsze zgodne z reszta bazy.

Co o tym myslicie? Może macie inne pomysły na rozwiazanie tego problemu?
wookieb
1) struktura tabel
2) zapytanie
3) moc indeksów
Tego nam brakuje do powiedzenia czegokolwiek więcej.
nospor
4) EXPLAIN (chyba że pod 3 to miałeś na myśli smile.gif )

ps: produkt może należeć do kilku sklepów?
madar
Tak, produkt jest przypisany do wielu sklepów, a kazdy sklep jest przypisany do jednej sieci. poniewaz produkt jets przypsiany do wielu sklepow, to tabela produkt2sklep rozrosla sie do takiej wielkosci.

W każdym razie obrazowo tabele wygladaja tak:

PRODUKT
id_produktu
...

SKLEP
id_sklepu
nazwa
id_sieci
...

SIEC
id_sieci
...

PRODUKT2SKLEP
id_produktu
id_sklepu


Tabela, ktora chce wprowadzic to:

PRODUKT2SIEC
id_produktu
id_sieci


ZAPYTANIE (pseudokod):
SELECT * FROM produkt
INNER JOIN produkt2sklep ON id_produktu=id_produktu
INNER JOIN sklep ON id_sklepu=id_sklepu
INNER JOIN siec on id_sieci=id_sieci
WHERE id_sieci=8

A po amianach byloby:
SELECT * FROM produkt
INNER JOIN produkt2siec ON id_sieci=id_sieci
INNER JOIN siec on id_sieci=id_sieci
WHERE id_sieci=8

Pobieram wybrane kolumny, nie wszystkie.
Indexy sa nalozone na wszytskich polach, ktore sa pobierane i uzywane w WHERE i JOIN.
Przejalem ten projekt, moce indexow sa poustawiane przez innych, musze doczytac o ich istotnosci - czy moc indexow duzo zmienia?
sniver
jakie to typy tabel?
masz klucze, indeksy pozakladane? Jeśli tak to może za mało komumn jest powstawianych do indeksów...
jeśli masz innodb to może "klucze obce" wykorzystaj - nie wiem czy coś tu pomogą, ale nie zaszkodzą...
nospor
Cytat
indeksy pozakladane?
Nie nie zakładał. Przecież napisał tylko:
Cytat
Dodam, że używam indexów tam, gdzie potrzeba.

Cytat
Indexy sa nalozone na wszytskich polach, ktore sa pobierane i uzywane w WHERE i JOIN.


@madar prosiłem jeszcze o EXPLAIN z zapytania
wookieb
To, że założysz indeks na kazdym polu kompletnie nic nie znaczy.
1) strukture tabeli pokazuje się w ten sposób
  1. SHOW CREATE TABLE 'tabela';

I wklejasz nam
2) Indeksy oraz moc pokazujesz w ten sposób http://dev.mysql.com/doc/refman/5.0/en/show-index.html
3) a gdzie explain z zapytania?
4) P.s 8mln to nie jest tak dużo danych
madar
Ok, chcialem uniknac wnikania w faktyczna strukture bazy, ale chyba nie obejdzie sie bez tego. Ponizej potrzebne dane. Tabela "visit" to produkty, "site" to sklepy. Jesli cos bedzie niezrozumiale prosze o info

  1. visit CREATE TABLE `visit` (
  2. `id_v` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `id_p2s_v` int(10) UNSIGNED NOT NULL,
  4. `date_from_v` date NOT NULL,
  5. `time_v` time DEFAULT NULL,
  6. `price_v` float NOT NULL,
  7. `avail_v` int(11) DEFAULT NULL,
  8. `date_to_v` date NOT NULL,
  9. `promotion_id_v` int(10) UNSIGNED DEFAULT NULL,
  10. `added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  11. `author_id` int(11) DEFAULT '2147483646',
  12. `v_accepted` int(11) NOT NULL DEFAULT '3' COMMENT '1 tak ; 2 nie ; 3 nieocenione;',
  13. PRIMARY KEY (`id_v`),
  14. UNIQUE KEY `id_product_v` (`id_p2s_v`,`date_from_v`,`date_to_v`,`promotion_id_v`),
  15. KEY `id_p2s_v` (`id_p2s_v`),
  16. KEY `price_v` (`price_v`),
  17. KEY `date_to_v` (`date_to_v`),
  18. KEY `date_from_v` (`date_from_v`),
  19. KEY `author_id` (`author_id`),
  20. KEY `v_accepted` (`v_accepted`),
  21. KEY `promotion_id_v` (`promotion_id_v`)
  22. ) ENGINE=MyISAM AUTO_INCREMENT=5905072 DEFAULT CHARSET=utf8



  1. visit2shop CREATE TABLE `visit2shop` (
  2. `v2s_id` bigint(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `v2s_shop` int(10) UNSIGNED NOT NULL,
  4. `v2s_visit` bigint(20) UNSIGNED NOT NULL,
  5. PRIMARY KEY (`v2s_id`),
  6. KEY `v2s_shop` (`v2s_shop`),
  7. KEY `v2s_prod` (`v2s_visit`)
  8. ) ENGINE=MyISAM AUTO_INCREMENT=120537533 DEFAULT CHARSET=utf8


  1. site CREATE TABLE `site` (
  2. `site_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `s_name` varchar(255) NOT NULL,
  4. `s_address` text NOT NULL,
  5. `s_active` enum('0','1') NOT NULL DEFAULT '1',
  6. `s_charset` varchar(10) DEFAULT NULL,
  7. `s_key_shop` tinyint(4) NOT NULL DEFAULT '0',
  8. `s_open_type` tinyint(1) DEFAULT '0' COMMENT '0-dowolne, 1-curl, 2-fsock',
  9. `s_network` int(10) UNSIGNED DEFAULT NULL,
  10. `s_city` int(10) UNSIGNED DEFAULT NULL,
  11. `s_extId` int(10) UNSIGNED DEFAULT NULL,
  12. `street` varchar(64) NOT NULL,
  13. `zipcode` varchar(6) NOT NULL,
  14. `lat` varchar(12) DEFAULT NULL,
  15. `lng` varchar(12) DEFAULT NULL,
  16. `open` varchar(5) DEFAULT NULL,
  17. `close` varchar(5) DEFAULT NULL,
  18. PRIMARY KEY (`site_id`),
  19. KEY `s_city` (`s_city`),
  20. KEY `s_network` (`s_network`)
  21. ) ENGINE=MyISAM AUTO_INCREMENT=36198 DEFAULT CHARSET=utf8



  1. network CREATE TABLE `network` (
  2. `network_id` int(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  3. `n_name` varchar(255) NOT NULL,
  4. `n_pic` int(10) UNSIGNED DEFAULT NULL,
  5. `nnt_type` int(10) UNSIGNED NOT NULL DEFAULT '0',
  6. `is_active` tinyint(1) NOT NULL DEFAULT '1',
  7. `external_id` int(10) UNSIGNED DEFAULT NULL,
  8. `added` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  9. `import` int(11) NOT NULL DEFAULT '1',
  10. PRIMARY KEY (`network_id`),
  11. KEY `n_name` (`n_name`)
  12. ) ENGINE=InnoDB AUTO_INCREMENT=284 DEFAULT CHARSET=utf8



  1. EXPLAIN SELECT id_v, id_p, name_p, specification, special, package, unit_count, unit, desc_p, price_v, n_pic, n_name, v_accepted, p2s_segment
  2. FROM visit
  3. INNER JOIN prod2seg ON id_p2s_v = p2s_id
  4. INNER JOIN segment ON id_s = p2s_segment
  5. INNER JOIN product ON id_p = p2s_product
  6. INNER JOIN visit2shop ON visit2shop.v2s_visit = id_v
  7. INNER JOIN site s1 ON visit2shop.v2s_shop = site_id
  8. INNER JOIN network ON s_network = network_id
  9. WHERE visit.author_id <>2147483646
  10. AND date_to_v >= '2011-07-15'
  11. AND date_from_v <= '2011-07-15'
  12. AND s1.s_network =6
  13. AND p2s_segment
  14. IN ( 452, 463, 503, 456, 454, 455 )
  15. GROUP BY id_v
  16. ORDER BY name_p ASC
  17. LIMIT 0 , 1


(sorry za format tego ponizej...)

id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE network const PRIMARY PRIMARY 4 const 1 Using temporary; Using filesort
1 SIMPLE s1 ref PRIMARY,s_network s_network 5 const 143 Using where
1 SIMPLE visit2shop ref v2s_shop,v2s_prod v2s_shop 4 hiper_stage.s1.site_id 457
1 SIMPLE visit eq_ref PRIMARY,id_product_v,id_p2s_v,date_to_v,date_from_... PRIMARY 8 hiper_stage.visit2shop.v2s_visit 1 Using where
1 SIMPLE prod2seg eq_ref PRIMARY,unikalny,p2s_segment,p2s_product PRIMARY 4 hiper_stage.visit.id_p2s_v 1 Using where
1 SIMPLE product eq_ref PRIMARY PRIMARY 4 hiper_stage.prod2seg.p2s_product 1
1 SIMPLE segment eq_ref PRIMARY PRIMARY 4 hiper_stage.prod2seg.p2s_segment 1 Using index


zrzut explaina:





Widzę, że jednak opis jest zbyt szczegółowy. Tak czy inaczej zdecydowałem się na wykorzystanie dodatkwoej tabeli - wykonanie zapytania trwa teraz około 100 razy szybciej (srednio z 3 s na 0,03s), co jest juz dla mnei zadowalajacym wynikiem i póki co tak to zostawię.
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2025 Invision Power Services, Inc.