Autor | Zpráva | ||
---|---|---|---|
tatyalien Profil |
#1 · Zasláno: 18. 11. 2009, 00:03:39
Dobrý večer,
řeším následný problém. Mám 2 tabulky v mysql. Z první tabulky si vytáhnu data pomocí selectu, pak v proceduře: while ($zaznam = MySQL_Fetch_Array($vysledek)) Nejdříve jsem to řešil, že jsem v této smiččce si připravil data a vždy poslal příkaz update do tabulky číslo 2, ale je to časově náročné a vždy to skončilo maximální dobou zpracování, když jsem koukal, tak 10 záznamů to udělalo za cca 4s při tomhle tempu by to bylo cca 94min :-D a to je fakt moc... tak jsem si říkal, že to zkusím pomcí multi_query. Tam to vypadalo o dost lépe, v proceduře jsem si jen poskládal dotazy do řetězce typu: query = "UPDATE tabulka SET Sloupec1= 'Data1', Sloupec2= 'Data2' WHERE VyhledavaciSloupecA= 'xxx' AND VyhledavaciSloupecB= '' LIMIT 1;"; tohle funguje, ale jakmile to překročí určitou hranici (někdy se to sekne na 4000, někdy na 5000 záznamech (jen jsem to zkoušel pomocí selectního limitiu po částech): $vysledek = mysql_query("select sloupecA, sloupecB, sloupecC, sloupecD from tabulkaA LIMIT 1000", $link); if (mysql_num_rows($vysledek) == 0) { echo "nenalezeno"; } else { while ($zaznam = MySQL_Fetch_Array($vysledek)): // zde připravím data endwhile; }; // tady si připravím dotaz na multi_query... $mysqli = new mysqli("localhost", "uzivatel", "heslo", "dtb"); $mysqli->set_charset('utf8'); // kontrola pro mě, zda je příkaz ok echo "<pre>" . $query . "</pre>"; if ( $mysqli->multi_query($query) ) { echo "<br>SQL DOTAZ je OK<br>"; } else { echo "<br>něco je špatně query<br>"; }; nevíte jak udělat, aby to všechno prošlo, nebo zda mám udělat více proměnných $query a ty pak postupně pomocí multi_query odesílat do db (to mě přijde praštěný), ale třeba přeteče nějaká paměť, nebo co já vím :-(. Nebo není nějak i možnost aby mě to vypsalo při jakém dotazu to klekne? Když to dělám "jednorázově" tak tam se to jednoduše ošetří $result = mysql_query($query); if (!$result) { return "ERROR - Katalog \"$KatalogNaChybu\" nelze opravit (UpdateTabulky).<br>\r\n"; } ale jak to zakomponovat do tohohle mě teď vůbec nenapadá :-( |
||
Alphard Profil |
#2 · Zasláno: 18. 11. 2009, 06:10:39
Pohled z jiné strany. Jak složité je to zpracování? Nešlo by přepsat do SQL procedury? MySQL (43) - Uložené procedury - Linux Software
|
||
nightfish Profil |
#3 · Zasláno: 18. 11. 2009, 06:57:31
tatyalien:
„WHERE VyhledavaciSloupecA= 'xxx' AND VyhledavaciSloupecB= ''“ existují na uvedených sloupcích indexy? případně ještě lépe složený index na obou? aktualizace 10 záznamů za 4 s v tabulce se 14000 záznamy je strašně pomalá |
||
tatyalien Profil |
#4 · Zasláno: 18. 11. 2009, 08:41:29
index je jeden na 2 sloupce, jelikoz ve sloupci VyhledavaciSloupecA jsou duplicity a rozdeluji se pouze podle VyhledavacihoSloupceB (v nem jsou rozdeleny dle textu, popripade prazdne hodnoty)
SQL proceduru neznám, juknu na to... |
||
tatyalien Profil |
#5 · Zasláno: 18. 11. 2009, 10:49:32
Alphard:
Tak na procedury jsem koukal, ale nějak mě to nejde, nejdou ani vytvořit v phpmyadminu, ten mě sice ukazuje # Verze MySQL: 5.1.33-community, # Verze protokolu: 10. Ve článku co jsi mě zde dával MySQL (43) - Uložené procedury - Linux Software tak tam je psáno, že to je od verze 5 vejš a to dle tohohle mám. Možná nevím kde to mám asi zadávat, jsem to tam zkoušel pod SQL příkazama. |
||
tatyalien Profil |
#6 · Zasláno: 18. 11. 2009, 11:51:37
Tak jsem udělal i update xampu, kde je teď mysql přez phpmyadmin
# Verze MySQL: 5.1.37, # Verze protokolu: 10 ale stále procedury nějak nejdou :-( |
||
tatyalien Profil |
#7 · Zasláno: 18. 11. 2009, 12:53:45
Tak jsem se dočetl:
Proceduru vložte například v konsoli (mysql -u uzivatel -p heslo) úplně stejně jako jiný SQL kód (nejdříve je třeba si zvolit databázi: use nazev_databaze) s tím, že je nejdříve třeba použít příkaz DELIMITER //, aby vám konsole nezalamovala řádky jako nové příkazy; phpMyAdmin zatím vkládat nebo prohlížet procedury neumí. |
||
Alphard Profil |
#8 · Zasláno: 18. 11. 2009, 13:53:31
tatyalien:
Proceduru lze určitě vytvořit i mimo konzoli, pokud to podporuje vaše verze MySQL. phpMyAdmin nepoužívám, ale třeba Adminer (dříve phpMinAdmin) to umí. Jde spíše o to, jestli jsou procedury vhodným řešením. Pomohlo by, kdybyste sem dal celý cyklus while ($zaznam = MySQL_Fetch_Array($vysledek)) Jestli tam nejsou nejsou složité podmínky apod. tak by to šlo třeba i přepsat do složitějšího update dotazu. |
||
tatyalien Profil |
#9 · Zasláno: 18. 11. 2009, 14:51:36 · Upravil/a: tatyalien
Zkoušel jsem i verzy kde v kódu odesílám rovnou data do db kde je nahrazeno
$query .= UpdateTabulkyMysqlLike("goods_opravena",$HodnotyZmenit,$HodnotyHledat,$KatalogHledat,1); Tak tady je celý while.. while ($zaznam = MySQL_Fetch_Array($vysledek)): $i++; $HodnotyZmenit = array(); $HodnotyZmenit["Nazev"] = "'" . saveDB(fun_Nazev($zaznam["nazev"], $zaznam["novinka"])) . "'"; // do proměnné uložím dlouhý popis $DlouhyPopis = fun_DlouhyPopis($zaznam["popiskratky"], $zaznam["obsahbaleni"], $zaznam["popisdlouhy"], $zaznam["technickeudaje"], $zaznam["doporucujemekoupit"]); // pokud není dlouhý popis prázdný, budu měnit data v DB if($DlouhyPopis!="") $HodnotyZmenit["Popis"] = "'" . saveDB($DlouhyPopis) . "'"; // pokud je zdaný krátký popis, budu ho měnit v DB if($zaznam["popiskratky"]!="") $HodnotyZmenit["KratkyPopis"] = "'" . saveDB($zaznam["popiskratky"]) . "'"; $Katalog = str_replace("/","$",$zaznam["kod"]); $HodnotyHledat = "IndexA LIKE '___-$Katalog' AND CenovaHladinaID = ''"; /* katalog musím hledat dle like jelikož bych musel zde dělat další dotaz do sql na "zkratku" dodavatele, tak to raději dám pomocí LIKE kde dám první tři znaky jakékoliv ___ */ $KatalogHledat = "___-$Katalog"; /* zde si spojím data pro multi query, zkoušel jsem i verzy bez multi query a rovnou odesílal dotaz do mysql */ $query .= UpdateTabulkyMysqlLike("goods_opravena",$HodnotyZmenit,$HodnotyHledat,$KatalogHledat,1); // promazání hodnot unset($HodnotyZmenit); unset($HodnotyHledat); unset($DlouhyPopis); unset($Katalog); endwhile; kde ještě volám pár funkcí, které mě jen upraví obsah, jena z nich je fun_DlouhyPopis, která jen poskládá data ze sloupců a naformátuje do html, funkce: UpdateTabulkyMysqlLike je zde: /** <------------------------ UPDATE MYSQL S LIKE ------------------------> */ function UpdateTabulkyMysqlLike($tabulka, array $HodnotyZmenit, $HodnotyHledatRetezec, $LimitCislo = "") { // poskládání hodnot typu klíč = hodnota array_walk($HodnotyZmenit, create_function('&$val, $key', '$val = "$key = $val";')); // vytvoření dotazu, implode spojí hodnoty dle rozdělovače $query = "UPDATE $tabulka SET " . implode(", ", $HodnotyZmenit) . " WHERE $HodnotyHledatRetezec"; if ($LimitCislo != "") $query .= " LIMIT $LimitCislo"; $query .= ";"; return $query; }; snad pomůže... :-( já už nevím..., Jinak procedura co jsem koukal se vložila pomocí phpmyadmin, ale není tam vidět, ale je tam (jsem jen zkoušel dle webu tu jednoduchou)... |
||
tatyalien Profil |
#10 · Zasláno: 19. 11. 2009, 18:13:17
Nevíte tedy jak to udělat :-(?
|
||
Alphard Profil |
#11 · Zasláno: 19. 11. 2009, 20:25:34
tatyalien:
„Nevíte tedy jak to udělat :-(?“ Hmm, ten kód je dost neprůhledný, několikrát jsem ho četl a stejně z toho moc moudrý nejsem. A nikdo jiný sem taky nepíše. Jak vypadá ten výsledný update? Kdyby se podařilo trochu to zrychlit, mohlo by stačit multi_query třeba po tisíci. Pokud se to nepovede, nešlo by spouštět tuto akci postupně? Stejně to vypadá spíš na nějaku servisní opravu tabulky. |
||
tatyalien Profil |
#12 · Zasláno: 20. 11. 2009, 09:14:28
Je to aktualizační oprava DB dle údajů od dodavatele, oprava popisků a obrázků. Kde dává v souborech nová data.
Asi to budu muset spouštět postupně třeba po 1000 záznamech ať mám jistotu, ale to mě nepřijde moc dobré vyřešení problému, ale co nadělám :( |
||
tatyalien Profil |
Moderátor Chamurappi: Přesunuto z Oprava tabulky pomocí jiné (cca 14 000 záznamů...).
Dobrý den, mám dotaz, jak udělat následné: Mám 2 tabulky (pro přklad tabulkaA a tabulkaB) v mysql které obsahují dost záznamů cca 14 000. Potřebuji aby se tabaulkA opravila dle tabulkyB (ale pouze jen některé sloupce), potřebuji z tabulkyB si poskládat data a ty upravit v tabulceA. Když jsem to zkoušel pomocí vytáhnutí dat z tabulkyB v php a "poskládání dat" tak jak potřebuji a updatovat tabulkuA tak to je časově dosat náročné a nereálné. Tak jsem zkusil updatovat pomocí multi_query, tam to bylo již nadějné, ale někdy to klekne při 4000 záznamech, někdy při 5000 (asi přeteče nějaká paměť)... |
||
Joker Profil |
Moderátor Chamurappi: Přesunuto z Oprava tabulky pomocí jiné (cca 14 000 záznamů...).
14000 záznamů není zase tak moc. Co přesně znamená „aby se tabaulkA opravila dle tabulkyB“? Co se má udělat? |
||
tatyalien Profil |
Moderátor Chamurappi: Přesunuto z Oprava tabulky pomocí jiné (cca 14 000 záznamů...).
Joker: TabulkaB obsahuje ve sloupcích například popis_krátký, popis_dlouhý,. dop. přísluško, názvy, obrázky. TabulkaA je co vše mám na webu za zboží TabulkaA se potřebuje opravit dle novejch dat od dodavatele, v tabulceA je pak jen jeden sloupec pro KrátkýPopis, DlouhýPopis a obrázky. takže si z tabulkyB potřebuji vzít data, ty si pospojovat dle libosti (naformátování do html kódu) a pak uložit. sloučení záznamů mám dle "kódu" kde v tabulceB je jen část a v tabulceA má ještě znaxy "xxx-" takže to opravuji pomocí "LIKE ___-" |
||
Kajman_ Profil * |
#16 · Zasláno: 20. 11. 2009, 09:47:07
Co zkusit něco takového?
update a using tabulka_kompletni a join tabulka_dodavatele b on a.klic=b.klic set a.sloupec5=b.sloupec5, a.sloupec7=b.sloupec7 |
||
tatyalien Profil |
#17 · Zasláno: 20. 11. 2009, 09:58:21
Kajman_:
toto je jestli se nepletu spojení tabulek, kde nahradím sloupce hodnotama z další tabulky. Ale já je nemůžu nahradit přímo tím sloupcem, ale poskládaním řetězce z několika sloupců) |
||
Kajman_ Profil * |
#18 · Zasláno: 20. 11. 2009, 10:01:06
Spojit sloupce dokáže funkce concat.
update a using tabulka_kompletni a join tabulka_dodavatele b on a.klic=b.klic set a.sloupec5=concat(b.sloupec5,b.sloupec7) |
||
tatyalien Profil |
#19 · Zasláno: 20. 11. 2009, 10:12:09
Kajman_
Oki juknu na to ;) |
||
tatyalien Profil |
#20 · Zasláno: 20. 11. 2009, 11:44:55
Tak tohle jsem rozchodil jen s osekanou verzí bez using (s ní mě to neprošlo v phpmyadmin)
update tabulkaa a join tabulkab b on a.a1=b.b1 set a.a2=concat(b.b2,b.b3) ale nevím jak rozchodit aby v podmínce bylo něco jako a.a1 LIKE "___-" b.b1 a u tohoto řešení si nemůžu stejně naformátovat to spojení concat (kde si sloupce formátuji do html kódu, typu b.b2 dodat pak 2x "<br>" a pak b.b3 atd..) |
||
tatyalien Profil |
#21 · Zasláno: 20. 11. 2009, 12:12:28
Tak pro lepší přehled kódu jsem redukoval zadání:
Použité funkce: fun_DlouhyPopis function fun_DlouhyPopis($popiskratky, $obsahbaleni, $popisdlouhy, $technickeudaje, $doporucujemekoupit){ // zde si upravím proměnné do html kódu, pro zjednodušení je zde jen tělo funkce // odeslání dat zpět pomocí funkce return $PomocnyText; }; fun_Nazev function fun_Nazev($nazev, $novinka){ return ($novinka=="ne") ? "$nazev" : "Novinka - $nazev"; }; ochrana uložení do db: function saveDB($value){ return mysql_real_escape_string(trim($value)); } ; funkce, která skládá dotaz do mysql na update, tato funkce vrátí pro příklad následující řětězec UPDATE tabulka SET Nazev = 'aaa', Popis = 'bbbb' WHERE IndexA LIKE '___-Katalog' AND CenovaHladinaID = '' LIMIT 1; function UpdateTabulkyMysqlLike($tabulka, array $HodnotyZmenit, $HodnotyHledatRetezec, $LimitCislo = "") { // poskládání hodnot typu klíč = hodnota array_walk($HodnotyZmenit, create_function('&$val, $key', '$val = "$key = $val";')); // vytvoření dotazu, implode spojí hodnoty dle rozdělovače $query = "UPDATE $tabulka SET " . implode(", ", $HodnotyZmenit) . " WHERE $HodnotyHledatRetezec"; if ($LimitCislo != "") $query .= " LIMIT $LimitCislo"; $query .= ";"; return $query; }; Nyní skrypt na upgrad databáze: $time_start = microtime(true); echo "Vytvořeno: " . date("d.m.y G:i:s") . "<br>\r\n"; echo "---------------------------------------------------------------<br>\r\n"; // $i - jen pro info kolik záznamů se zpracovalo $i = 0; $vysledek = mysql_query("select kod, nazev, novinka, popiskratky, obsahbaleni, popisdlouhy, technickeudaje, doporucujemekoupit from seznam_polozek", $link); // pokud se nevrátil žádný záznam z dotazu vypížu že se nic nenalezlo if (mysql_num_rows($vysledek) == 0) { echo "nenalezeno"; } else { // jinak projedu záznamy, které se vrátili while ($zaznam = MySQL_Fetch_Array($vysledek)): $i++; /* nyní připravím pole typu název sloupce - hodnota pro věci, které budu měnit*/ $HodnotyZmenit = array(); $HodnotyZmenit["Nazev"] = "'" . saveDB(fun_Nazev($zaznam["nazev"], $zaznam["novinka"])) . "'"; // do proměnné uložím dlouhý popis $DlouhyPopis = fun_DlouhyPopis($zaznam["popiskratky"], $zaznam["obsahbaleni"], $zaznam["popisdlouhy"], $zaznam["technickeudaje"], $zaznam["doporucujemekoupit"]); // pokud není dlouhý popis prázdný, budu měnit data v DB if($DlouhyPopis!="") $HodnotyZmenit["Popis"] = "'" . saveDB($DlouhyPopis) . "'"; // pokud je zdaný krátký popis, budu ho měnit v DB if($zaznam["popiskratky"]!="") $HodnotyZmenit["KratkyPopis"] = "'" . saveDB($zaznam["popiskratky"]) . "'"; $Katalog = str_replace("/","$",$zaznam["kod"]); // Proměnná $HodnotyHledat je vyhledávací podmínka, kde musím použít like, protože v cílové tabulce je kagalog typu xxx-katalog $HodnotyHledat = "IndexA LIKE '___-$Katalog' AND CenovaHladinaID = ''"; $KatalogHledat = "___-$Katalog"; // ze připravím řetězec pro multi_query $query .= UpdateTabulkyMysqlLike("goods_opravena",$HodnotyZmenit,$HodnotyHledat,1); // promazání hodnot unset($HodnotyZmenit, $HodnotyHledat, $DlouhyPopis, $Katalog); endwhile; } $mysqli = new mysqli("localhost", "root", "", "db_test"); $mysqli->set_charset('utf8'); if (mysqli_connect_errno()) { printf("Připojení se nezdařilo: %s\n", mysqli_connect_error()); exit(); }; if ( $mysqli->multi_query($query) ) { echo "<br>SQL DOTAZ je OK query<br>"; } else { echo "<br>něco je špatně query<br>"; }; /* close connection */ $mysqli->close(); $time_end = microtime(true); $time = $time_end - $time_start; echo "---------------------------------------------------------------<br>\r\n"; echo "Načteno v microsekunách: $time<br>\r\n"; echo "Celkem: $i<br>\r\n"; Toto funguje, ale někdy to padne při 4000, někdy při 5000 záznamech :-( |
||
Kajman_ Profil * |
#22 · Zasláno: 20. 11. 2009, 12:16:03
Jo to using je asi jen v delete, pardon. S tím like to bude asi šíleně pomalé.
update tabulkaa a join tabulkab b on a.a1 like concat('___-',b.b1) set a.a2=concat(b.b2,'<br><br>',b.b3) |
||
tatyalien Profil |
#23 · Zasláno: 20. 11. 2009, 12:26:05 · Upravil/a: tatyalien
Kajman_
Tak tohle by myslím šlo ;) zkusím to zakomponovat... Ohledně like... pokud bych to nědělal pomocí like, tak bych musel vkládat dotaz do dtb na název výrobce a dohledání jeho "zkratky" což by podle mě bylo pomalejší (další select). podmínka asi v concat asi nemůže být viď :-D |
||
Kajman_ Profil * |
#24 · Zasláno: 20. 11. 2009, 12:28:17
Tak si pak můžete zkusit, jestli update s další tabulkou nebude rychlejší než to like.
|
||
tatyalien Profil |
#25 · Zasláno: 20. 11. 2009, 13:17:06
No zkusím to rozdhodit zatím na tohle popřípadě pak zkusím s tím dalším selectem... jen ještě jedna triviálnost :-) jak do toho dotazu:
update tabulkaa a join tabulkab b on a.a1 like concat('___-',b.b1) set a.a2=concat(b.b2,'<br><br>',b.b3) dodat ve vyhledávací podmínce a.a1 like concat('___-',b.b1) ještě " AND a.3=''); |
||
nightfish Profil |
#26 · Zasláno: 20. 11. 2009, 13:28:53
update ... join ... set ... where a.a3 = '' |
||
tatyalien Profil |
#27 · Zasláno: 20. 11. 2009, 13:32:07
nightfish
Díky, tuhle jedinou možnost jsem nezkusil :-D |
||
Kajman_ Profil * |
#28 · Zasláno: 20. 11. 2009, 14:19:22
tuhle jedinou možnost jsem nezkusil
Asi nebude jediná. on a.a1 like concat('___-',b.b1) AND a.a3='' |
||
tatyalien Profil |
#29 · Zasláno: 20. 11. 2009, 15:09:50
Tak stejně po 20 minutách jsem to vzdal a příkaz ukončil... :-(, procík na 70% 20min už bylo moc...
Kajman_ on a.a1 like concat('___-',b.b1) AND a.a3='' jsem zkoušel ale neprošlo mě to :-) |
||
Kajman_ Profil * |
#30 · Zasláno: 20. 11. 2009, 15:33:43
Co přidat tu třetí tabulku definující prefix výrobce? Tipnul bych, že to může urychlit.
Také může být rychlejší vytvořit si na základě tabulky b a tabulky výrobců dočasnou tabulku c, kde už budou texty upraveny přesně pro použití pro tabulku a :-) |
||
Téma pokračuje na další straně.
|
0