« 1 2 »
Autor Zpráva
tatyalien
Profil
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))
si data upravím dle libosti, a těmito datama potřebuji opravit tabulku číslo 2. Problém je v tom, že záznamů je cca 14 000.

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
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
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
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
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
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
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
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
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);
za dotaz, který nevrací "příkaz" ale rovnou ho odešle, ale doba je dle toho co jsem psal víše na 93 minut (by oko...), tady ta verze je se složením příkazu pro multi_query.

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
Nevíte tedy jak to udělat :-(?
Alphard
Profil
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
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 *
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
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 *
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
Kajman_
Oki juknu na to ;)
tatyalien
Profil
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
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 *
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
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 *
Tak si pak můžete zkusit, jestli update s další tabulkou nebude rychlejší než to like.
tatyalien
Profil
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
update ... join ... set ... where a.a3 = ''
tatyalien
Profil
nightfish
Díky, tuhle jedinou možnost jsem nezkusil :-D
Kajman_
Profil *
tuhle jedinou možnost jsem nezkusil
Asi nebude jediná.
on  a.a1 like concat('___-',b.b1) AND a.a3=''
tatyalien
Profil
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 *
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 :-)
« 1 2 »

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0