Nové číslo časopisu Raspberry Pi zdarma ke čtení: Raspberry Pi Official Magazine 156 (pdf).
Armbian, tj. linuxová distribuce založená na Debianu a Ubuntu optimalizovaná pro jednodeskové počítače na platformě ARM a RISC-V, ke stažení ale také pro Intel a AMD, byl vydán ve verzi 25.8.1. Přehled novinek v Changelogu.
Včera večer měl na YouTube premiéru dokumentární film Python: The Documentary | An origin story.
Společnost comma.ai po třech letech od vydání verze 0.9 vydala novou verzi 0.10 open source pokročilého asistenčního systému pro řidiče openpilot (Wikipedie). Zdrojové kódy jsou k dispozici na GitHubu.
Ubuntu nově pro testování nových verzí vydává měsíční snapshoty. Dnes vyšel 4. snapshot Ubuntu 25.10 (Questing Quokka).
Řada vestavěných počítačových desek a vývojových platforem NVIDIA Jetson se rozrostla o NVIDIA Jetson Thor. Ve srovnání se svým předchůdcem NVIDIA Jetson Orin nabízí 7,5krát vyšší výpočetní výkon umělé inteligence a 3,5krát vyšší energetickou účinnost. Softwarový stack NVIDIA JetPack 7 je založen na Ubuntu 24.04 LTS.
Národní úřad pro kybernetickou a informační bezpečnost (NÚKIB) spolu s NSA a dalšími americkými úřady upozorňuje (en) na čínského aktéra Salt Typhoon, který kompromituje sítě po celém světě.
Společnost Framework Computer představila (YouTube) nový výkonnější Framework Laptop 16. Rozhodnou se lze například pro procesor Ryzen AI 9 HX 370 a grafickou kartu NVIDIA GeForce RTX 5070.
Google oznamuje, že na „certifikovaných“ zařízeních s Androidem omezí instalaci aplikací (včetně „sideloadingu“) tak, že bude vyžadovat, aby aplikace byly podepsány centrálně registrovanými vývojáři s ověřenou identitou. Tato politika bude implementována během roku 2026 ve vybraných zemích (jihovýchodní Asie, Brazílie) a od roku 2027 celosvětově.
Byla vydána nová verze 21.1.0, tj. první stabilní verze z nové řady 21.1.x, překladačové infrastruktury LLVM (Wikipedie). Přehled novinek v poznámkách k vydání: LLVM, Clang, LLD, Extra Clang Tools a Libc++.
Řešení dotazu:
Trošku teorie:
Většinou je lepší použít méně selektů než více. Pokud například pracuješ s velkými objemy dat a použiješ z nej jen pár záznamů, potom je ale lepší použít více selektů.
V tvém případě procházíš stejně všechny data a všechny je budeš zpracovávat, proto použij jeden selekt a pouze projekce (vybre jen ty sloupce, které potřebuješ).
Dále použij mysql_* pro procházení dat:
$res = mysql_query('select ...') while(($row = mysql_fetch_array($res)) { }Tady je hezký příklad: http://www.php.net/manual/en/function.mysql-fetch-array.php
SELECT
. Už proto, že kdyby během zpracování každého z těch 3000 mohlo docházet k modifikacím seznamu uživatelů, mohl by v datech vzniknout zmatek. Také by se mohlo případně stát, že by se to "niečo" provedlo jen pro některé uživatele a pro jiné ne.
Uvědom si, že každý SELECT
se kompiluje do pseudokódu a teprve ten se provádí. Pokud se dá příkaz napsat jako jeden SELECT
, je to k databázi mnohem šetrnější a výkonnější. Navíc celá akce proběhne atomicky.
Systémové prostředky by to zahltit nemělo, protože PHP si data z databáze odebírá postupně jak potřebuje. Obvykle bývá nastaven limit paměti pro proměnné v PHP na 32 MB, ale dá se zpracovat i select se stovkami MB.
Spíš bych se ale zamyslel nad tím: Co vlastně s těmi daty potom děláš? Neukládáš je po modifikaci opět do databáze? To bych v cyklu rozhodně nedělal, ale nechal bych to udělat přímo tu databázi.
dotaz na nějakejch 15kB a výsledek ne o moc víc... + len krátke textové veci, mená, emaily, čísla, dátumyMůže ve výsledku znamenat i více než 0.3 MiB.
Budu ho normálně zpracovávat řádku po řádceJestli myslíš fetch_xxx, tak to na věci nic nemění, že data jsou v result setu načtena všechna.
mysql_unbuffered_query()
nedělá to, že by neukládala výsledek na straně klienta, ona ho jen nepřipravuje pro použití v PHP (nedělá z něj typy PHP) a umožňuje zpracování, hned jakmile už nějaká data dojdou. To znamená, že můžete získat rychlost, díky paralelnímu zpracování a ušetřit nějakou paměť díky „nepřekládání dat“, pokud budete dostatečně rychle zpracovávat (což ale v PHP asi těžko půjde předběhnout takový typ dotazu.), ale ty data na straně klienta uložena jsou, jen je hned odebíráte a nejsou tak velká (zvláště pokud je tam spousta smallint, tinyint apod.).mysqli_result::free()
, mysqli_stmt::free_result()
nebo i třeba imagedestroy()
uvolňují prostě paměť ihned, řekněme mimo vyhledávací loop GC.
//pripojení k db
echo memory_get_usage(),"\n";
//$q=mysql_query("SELECT * FROM invoices");
$q=mysql_unbuffered_query("SELECT * FROM invoices"); \\ LIMIT 4000");
sleep(2);
echo memory_get_usage(),"\n";
$s=0;
while($r=mysql_fetch_row($q))
{
$s=$s+$r[0];
//echo memory_get_usage(),", ";
}
echo memory_get_usage(),"\n";
echo memory_get_peak_usage(),"\n";
exit();
Výsledky s normálním dotazem:
685984 4825840 4825840 44789896 44796976s buffered s limitem 4000
686000 1688464 1688464 11289208 11296256výsledky s unbuffered query
685800 695904 695904 696632 716056unbuffered s limitem 4000
686008 689696 689696 690256 715968unbuffered s limitem 20
685816 695920 695920 696648 715216Myslím, že tato data Tvoje tvrzení prostě vyvrací: spotřeba paměti je při unbuffered query defakto identická při 20 i 18000 záznamech. Navíc, kdyby to bylo tak, jak tvrdíš, tak by se data během sleepu načetly a spotřebovali paměť, tam ale k žádnému nárůstu paměti nedochází, k tomu dochází až u buffered query během cyklu. Proto je evidentní, že ani buffered query netahá všechna data hned, pouze je na straně klienta cachuje v okamžiku, kdy jsou poprve přečtena, aby umožnil pohyb zpět po resultsetu (samozřejmě tahá data po "paketech", proto je spotřeba paměti během cyklu vždy pár kroku stejná a pak skočí).
memory_get_usage()
a nebo se použije v PHP něco jako:
$pid = getmypid(); exec("ps -eorss,pid | grep $pid", $output); echo IntVal(trim($output[0])) * 1024,"\n";Takže je blbost co jsem psal v 1. odstavci a o čem jsem byl přesvědčen (nevím proč) a musel jsem se podívat i do zdrojáků PHP-ka a to i do starších verzí (4.x), ale nenašel jsem nic co by odpovídalo tomu co jsem psal, PHP funkce
mysql_unbuffered_query()
prostě a jednoduše odpovídá C API mysql_use_result().Conected and selected DB Exec ps: 6680576 Start mysql_query() Selected Exec ps: 41750528 Selected after sleep(2) Exec ps: 41750528 Fetched all rows, php sum(id): 16200090000 Exec ps: 41750528 After mysql_free_result Exec ps: 6680576 After mysql_close Exec ps: 6680576U
mysql_buffered_query()
to nabýšení na 40MiB nebylo.No generovat tabulku v databázi bych fakt nedooporučoval. Logika v databázi, to ano, ale view? To se bude tak obtížně spravovat, že fuj.Zrovna jsem to otestoval v SQLite na 300 000 záznamech. Vygenerování celé tabulky jedním selectem do jednoho řetězce bylo asi 3x rychlejší, než klasické procházení výsledků selectu cyklem. Možná se to obtížněji spravuje, ale databáze udělá view rychleji než PHP.
foreach($dbh->query("SELECT value as val FROM pokus;") as $row) { echo 'trtd'.$row['val'].'/td/tr'."\n"; }Skládání řádek v SQL (12 sekund):
foreach($dbh->query("SELECT 'trtd'||value||'/td/tr\n' as val FROM pokus;") as $row) { echo $row['val']; }Použití pole (9 sekund):
$out=array(); foreach($dbh->query("SELECT value as val FROM pokus;") as $row) { $out[]='trtd'.$row['val'].'/td/tr'; } echo implode("\n",$out);Použití řetězce (9 sekund):
$out=''; foreach($dbh->query("SELECT value as val FROM pokus;") as $row) { $out.='trtd'.$row['val'].'/td/tr'."\n"; } echo $out;Skládání řádek, kombinace s polem (9 sekund):
$out=array(); foreach($dbh->query("SELECT 'trtd'||value||'/td/tr' as val FROM pokus;") as $row) { $out[]=$row['val']; } echo implode("\n",$out);Agregace v SQL (5 sekund):
foreach($dbh->query("SELECT group_concat('trtd'||value||'/td/tr','\n') as val FROM pokus;") as $row) { echo $row['val']."\n"; }Agregace v SQL bez výstupu echo (2 sekundy):
foreach($dbh->query("SELECT group_concat('trtd'||value||'/td/tr','\n') as val FROM pokus;") as $row) { $line=$row['val']."\n"; }To poslední měření jsem uvedl proto, aby bylo vidět, jak je echo líné. Znaky
tr
a td
znamenají <tr>
a <td>
, ale nechtělo se mi to nahrazovat entitami v celém příspěvku. Kdo chce, domyslí si.
Skládání s polem máš naprosto zbytečně v cyklu, do implode můžeš hodit už ten query.Asi mi něco uniká. Myslíš něco takového?
$result=$dbh->query("SELECT 'trtd'||value||'/td/tr' as val FROM pokus;",PDO::FETCH_COLUMN)); echo implode("\n",$result->fetchAll());Zkusím to odladit, až budu na původním počítači. V této podobě by to mohlo být i rychlé. Ohledně údržby kódu: Někteří vývojáři tvrdí, že SQL umí všechno. Dá i nedá se s tím souhlasit, někdy je to za cenu velkých obstrukcí. Souhlasím, že je dobré dělat aplikace jako vícevrstvé, kód se tím často zpřehlední. V uvedeném případě mi však připadá přidání jedné funkce do SQL a ubrání z PHP jako jednoduchá úprava. Vychází mi však efektivnější. Můžu ještě zkusit porovnat i paměťové nároky jednotlivých řešení.
implode($dbh->query("SELECT 'trtd'||value||'/td/tr' as val FROM pokus;",PDO::FETCH_COLUMN, "\n")
ale to se omlouvám, zas jsem zapoměl na "debilitu" phpka, kde sice něco se tváří jako pole/iterátor, ale to ještě neznamená, že se to dá jako pole nebo iterátor používat, takže todle máš pravdu, to nejde.
Zkusit to s FetchAll je zajímavý, jestli je to fetchAll tedy napsané v něčem rozumějším než PHP, jinak to bude stejné.
V tý udržovatelnosti IMHO nejde až tak o to, že se to udělá jednou, ale o to, že např. za tejden přijde šéf, že chce, aby si mohl člověk tu tabulky "skinovat". V tu chvíli začne db řešení dělat problémy, protože tam se takový věci implantujou daleko hůř.
$result=$dbh->query("SELECT 'trtd'||value||'/td/tr' as val FROM pokus;",PDO::FETCH_COLUMN,0); echo implode("\n",$result->fetchAll());Je to asi nejrychlejší řešení z těch, které dělají výstupní agregaci mimo SQL. Zároveň nevypadá příliš složitě, mělo by být obecně použitelné. Předpokládám, že metoda fetchAll() je napsána v C nebo něčem podobném. Raději použiji takovou funkci než abych iteroval ve skriptu. Beru to od tebe jako dobrý nápad na rozumný kompromis. A že to má 2 řádky místo zamýšlené jedné? To mě vůbec netrápí. Zpracování skriptu v polovičním čase pro mne znamená zpracování dvojnásobného počtu požadavků klientů nebo pronajaté jedno procesorové jádro místo dvou. V případě některých aplikací to může být docela důležité. Jak už bylo řečeno, cokoliv je rychlejší než PHP. Tím cokoliv můžou být nejen databáze, ale i vestavěné funkce PHP, které obvykle v PHP napsány nejsou.
Tiskni
Sdílej: