ugrás a tartalomhoz

MySQL JOIN időköltsége (Hogyan ésszerűbb lekérdezni?)

laji · 2009. Okt. 8. (Cs), 11.48
Üdv mindenkinek!

Alapvetőnek tűnik, de nem sikerült választ találnom rá. A MySQL "EXPLAIN EXTENDED SELECT..." eredményét nem igazán sikerült értelmeznem.

Adott egy MySQLadattár:
  1. SET NAMES utf8;  
  2. CREATE TABLE `zokni` (  
  3.     `SORSZAM`   tinyint(4) unsigned NOT NULL default '0',  
  4.     `FAJTAKULCS`    tinyint(2) unsigned NOT NULL default '0',  
  5.     `SZINKULCS` tinyint(2) unsigned NOT NULL default '0',  
  6.     `LEIRAS_1`  varchar(45) COLLATE utf8_general_ci NOT NULL COMMENT 'ide jöhet pl. a gyártó',  
  7.     `LEIRAS_2`  text COLLATE utf8_general_ci NOT NULL COMMENT 'ecsetelgetem, milyen szép is ez',  
  8.     `AR`    tinyint(4) unsigned NOT NULL default '0' COMMENT 'az ár forintban',  
  9.     PRIMARY KEY (`SORSZAM`)  
  10.     KEY `FAJTAKULCS` (`FAJTAKULCS`),  
  11.     KEY `SZINKULCS` (`SZINKULCS`),  
  12. ) ENGINE=MyISAM COLLATE=utf8_general_ci;  
  13. INSERT INTO `zokni` VALUES (1, 1, 2, 'Egyesült Zokniművek Rt.''csodás benne a séta', 800);  
  14. INSERT INTO `zokni` VALUES (2, 2, 1, 'Alsókukutyinfalvi Zoknikunyhó''szinte ingyen', 100);  
  15. # ... stb. (3,000 tétel)  
  16.   
  17. CREATE TABLE `fajta` (  
  18.     `FAJTAKULCS`    tinyint(2) unsigned NOT NULL default '0',  
  19.     `FAJTA` varchar(128) COLLATE utf8_general_ci NOT NULL,  
  20.     PRIMARY KEY (`FAJTAKULCS`)  
  21. ) ENGINE=MyISAM COLLATE=utf8_general_ci;  
  22. INSERT INTO `fajta` VALUES (1, 'rövid szellős tavaszi');  
  23. INSERT INTO `fajta` VALUES (2, 'hosszú vastag téli');  
  24. # ... stb.  
  25.   
  26. CREATE TABLE `szin` (  
  27.     `SZINKULCS` tinyint(2) unsigned NOT NULL default '0',  
  28.     `SZIN`  varchar(128) COLLATE utf8_general_ci NOT NULL,  
  29.     PRIMARY KEY (`SZINKULCS`)  
  30. ) ENGINE=MyISAM COLLATE=utf8_general_ci;  
  31. INSERT INTO `szin` VALUES (1, 'piros, zöld pöttyökkel');  
  32. INSERT INTO `szin` VALUES (2, 'sárga, szürke csíkokkal');  
  33. # ... stb.  
A 3,000 tételből meg kell jelenítenem 20-at egy lapon. Mi a gyorsabb megoldás, mi használ kevesebb erőforrást?

1. lehetőség
  1. <?php  
  2. $eredmény_zokni=mysql_query("  
  3.     SELECT  zokni.*,  
  4.                 fajta.FAJTA,  
  5.                 szin.SZIN  
  6.     FROM        zokni LEFT JOIN (fajta, szin)  
  7.                 ON(  
  8.                     fajta.FAJTAKULCS=zokni.FAJTAKULCS  
  9.                     AND  
  10.                     szin.SZINKULCS=zokni.SZINKULCS  
  11.                 )  
  12.     ORDER BY    SORSZAM  
  13.     LIMIT       0, 20  
  14. ");  
  15. while ($sor_zokni=mysql_fetch_assoc($eredmény_zokni)) {  
  16.     echo     $sor_zokni["SORSZAM"]  
  17.             .$sor_zokni["FAJTA"]  
  18.             .$sor_zokni["SZIN"]  
  19.             .$sor_zokni["LEIRAS_1"]  
  20.             .$sor_zokni["LEIRAS_2"]  
  21.             .$sor_zokni["AR"];  
  22. }  
  23. ?>  
2. lehetőség
  1. <?php  
  2. $eredmény_zokni=mysql_query("  
  3.     SELECT  *  
  4.     FROM        zokni  
  5.     ORDER BY    SORSZAM  
  6.     LIMIT       0, 20  
  7. ");  
  8. while ($sor_zokni=mysql_fetch_assoc($eredmény_zokni)) {  
  9.     $fajta=mysql_result(mysql_query("SELECT FAJTA FROM fajta WHERE FAJTAKULCS=".$sor_zokni["FAJTAKULCS"]),0)  
  10.     $szín=mysql_result(mysql_query("SELECT SZIN FROM szin WHERE SZINKULCS=".$sor_zokni["SZINKULCS"]),0)  
  11.     echo     $sor_zokni["SORSZAM"]  
  12.             .$fajta  
  13.             .$szín  
  14.             .$sor_zokni["LEIRAS_1"]  
  15.             .$sor_zokni["LEIRAS_2"]  
  16.             .$sor_zokni["AR"];  
  17. }  
  18. ?>  
Előre is köszönöm a segítséget.
 
1

Harmadik lehetőség és megoldás

vbence · 2009. Okt. 8. (Cs), 12.35
Még egy versenyző:
  1. SELECT  zokni.*,    
  2.                 fajta.FAJTA,    
  3.                 szin.SZIN    
  4.     FROM        zokni, fajta, szin    
  5.     WHERE    
  6.                 fajta.FAJTAKULCS=zokni.FAJTAKULCS    
  7.                 AND    
  8.                 szin.SZINKULCS=zokni.SZINKULCS    
  9.     ORDER BY    SORSZAM    
  10.     LIMIT       0, 20  
A megoldás pedig, használj profiligot.

Az általad vázolt második lehetőségtől sírni fognak az angyalok :) Legalább
SELECT * FROM szin és SELECT * FROM fajta legyen az elején, ami egy-egy tömbbe gyűjti a szótártábláidat, majd ezekből a tömbökből a megflelő kulcshoz tartozó értéket írd ki.
(Amit felvázoltál az 41 lekérdezés, amihez 41szer fog lefutni a mysql SQL értlemezője, 41szer nyitja meg a táblákat stb stb stb...)
2

Bocs, nem voltam gépközelben.

laji · 2009. Okt. 8. (Cs), 15.57
Élesben, bonyolultabb adattárral nekem a javasolt 3. megoldás rögrön kiesett. A MySQL nem is volt hajlandó lefuttatni, 1104-es hibával tért vissza:
Message: The SELECT would examine more than MAX_JOIN_SIZE rows; check your WHERE and use SET SQL_BIG_SELECTS=1 or SET SQL_MAX_JOIN_SIZE=# if the SELECT is okay

A tömbbe gyűjtés ésszerűnek tűnik, bár egy régebbi kérdésemre, mi rendez gyorsabban, a PHP vagy a MySQL, a MySQL volt a válasz - tehát lehet, hogy nem is nyernék a tömbökkel. Végül is, a 2. megoldás 2 kis MySQL-lekérdezése is elég rövid, egysoros dolog. Közben új adattár-kapcsolatot nyitni természetesen nem kell, az él.
A hivatkozást köszönöm, kipróbálom; nekem nem sikerült ilyesmire bukkannom. Azért közben szívesen veszem mások tapasztalatait is.
4

Rendezés

vbence · 2009. Okt. 8. (Cs), 17.35
mi rendez gyorsabban


Ezt nem értem. Ki mondta, hogy PHP-ban kell rendezni?
5

Túl tömör voltam

laji · 2009. Okt. 8. (Cs), 17.50
Persze, rendezésről szó sincs. 1-2 éve kérdezősködtem itt egy találatsor eredményeinek rendezéséről (mert utf8-betűgondjaim voltak), s az akkori válaszokból azt szűrtem le, hogy a PHP sokoldalú, de ha nagy felsorolások kezeléséről van szó, akkor nagyságrendekkel lassabb, mint az arra kihegyezett adattárkezelő-nyelvek, tehát pl. a SQL. Másképp fogalmazva lebeszéltek arról, hogy adattömböket MySQL helyett PHP-vel faggassak - itt pedig épp erről lenne szó az ajánlatodban. Ezért merült fel bennem, hogy talán 41 MySQL-lekérdezés sem lesz lassabb, mint egyszer beolvasni egy PHP-tömbbe, s utána abból kérdezgetni le mindig.
3

Szerinem

gphilip · 2009. Okt. 8. (Cs), 16.47
A második megoldásod semmiképpen sem javasolt.

Szerintem

SELECT       zokni.*,  
             fajta.FAJTA,  
             szin.SZIN  
FROM         zokni
INNER JOIN   fajta   USING (FAJTAKULCS)
INNER JOIN   szin    USING (SZINKULCS)
ORDER BY     SORSZAM  
LIMIT        0, 20


INNER JOIN kulcsszavakkal sokkal átláthatóbb lesz a lekérdezés, és a JOIN-ok feltételei is egyértelműbbé válnak.

Ha rendesen indexelve van minden szükséges mező (FAJTAKULCS, SZINKULCS, SORSZAM), akkor ennek villámgyorsan le kell futnia egy 3000-es adatbázison (gondolom a fajták és sznek táblái nem túl nagyok)
6

Remélem, igazad van

laji · 2009. Okt. 8. (Cs), 18.08
..mert ez a szebb és kényelmesebb megoldás. A mutatóim [index] megvannak rendben, ezt igazolja a MySQL "EXPLAIN EXTENDED SELECT..." eredménye is. A fajták és színek táblái valóban nem nagyok, 100 sor alattiak.

Némi további magyarázat, miért is tetszene nekem is jobban a táblafűzéses megoldás [JOIN]: mert így pl. lehet rendezni a szín és a fajta szerint is rögtön ugyanabban az 1 lekérdezésben. Ez se megvetendő szempont.
7

Valóban az 1. a jó megoldás.

laji · 2009. Okt. 9. (P), 18.40
Fényesen bevált az 1. megoldás, pörög a MySQL. Köszönöm a segítséget mindkettőtöknek!

Még annyit: a USING szerkezetet azért nem használom, mert szándékosan eleve nincsenek egyező oszlopnevek még különböző táblákban sem; tehát a valós tábláimban még a FAJTAKULCS és SZINKULCS oszlopokat is másképp neveztem el a különböző táblákban. Oka: UNION szerkezetet is használok, s ott az egyező oszlopnév bonyodalmat okozna a rendezésnél (ORDER BY...).
8

Alias

Poetro · 2009. Okt. 9. (P), 21.49
Az alias-okat pont azért találták ki, hogy ne legyen abból probléma ha több táblában azonos mezőnév van. Példa:
  1. SELECT n.nid AS node_nid, c.nid AS content_nid   
  2. FROM node AS n   
  3. INNER JOIN content AS c USING vid   
  4. ORDER BY n.nid  
9

Hátránya is van

laji · 2009. Okt. 9. (P), 23.09
A főtáblám 25 oszlopból áll, további 4-10 oszlop a fűzött táblákból (JOIN). Ebből 10-15 szerint rendezek is (ORDER). Sok helyen lekérdezem a főtáblát. Így elég mindenütt SELECT zokni.* lekérés; ha álneveket (ALIAS) használnék, egyenként fel kéne sorolnom az összes oszlopot.

Rossz helyre szúrtam be a megjegyzést. :(