Autor | Zpráva | ||
---|---|---|---|
Tequily Profil |
#1 · Zasláno: 29. 10. 2012, 23:30:08
Zdravím,
mám takový dotaz, týkající se rychlosti. Vezměme v potaz, že UPDATE jednoho řádku trvá 0,0007s. Když je takovýchto dotazů prováděno 10000, matematicky mi vychází, že by dohromady měly trvat 7s. Nyní jsem ale importoval soubor, který obsahuje cca 48000 velmi jedoduchých dotazů, které vypadají zhruba takto: "UPDATE tabulka SET cosi = 'kde' WHERE (id = nějakéID AND posloupnost = 1)". Po cca 15 minutách se mi updatovalo pouze 12000 rádků. Jak je to tedy s rychlostí prováděných dotazů? Tohle mi totiž vážně nejde do hlavy. Děkuji za odpovědi, názory, komentáře. |
||
Kajman Profil |
#2 · Zasláno: 29. 10. 2012, 23:37:08
Zkuste si měřit rychlost updatů postupně pro všech 48000 řádků, zda se bude rychlost měnit.
Může to být např. tím, že malý počet se vejde do cache disku. U velkého počtu změn se již cache musí začít přepisovat na disk. |
||
Tori Profil |
Tequily:
Projevuje se to stejně i v situaci, kdy tabulka nemá žádné indexy? resp. je to spíš otázka na Kajmana: Může mít na rychlost vliv velikost indexu? Že např. velký index by se pomaleji updatoval než index pro pár řádků? (jestli by to tedy mohlo způsobovat rozdíl i u takhle relativně malého množství řádků) |
||
Tequily Profil |
#4 · Zasláno: 29. 10. 2012, 23:49:38
Tori:
To nevím, nezjišťoval jsem. Všechny tabulky jsou totiž indexovány pro maximální rychlost. Kajman: Ano, tím cachem by to mohlo být, to je dobrý nápad. Nicméně tu rychlost nezměřím, updatuji přes soubor a odstavil jsem si tím celé PMA dočasně :-) |
||
peta Profil |
"tabulky jsou totiž indexovány pro maximální rychlost"
Nezname strukturu tabulky, co je jak indexovano, nemame vzorek dat (5 radku) a nevime, jake sql dotazy vuci te tabulce posilas. Takze nelze rici, jestli jsou optimalizovany maximalne nebo si to jen myslis. (id = nějakéID AND posloupnost = 1) - pokud to pouzivat 48.000x, tak uz by se vyplatilo mozna pouzit index spolecny pro 2 sloupce. Mno, k veci. Napadlo mne, pouzivas to v transakci? Pokud commitujes radek po radku, tak to muze trvat 15 min a ne 7s. |
||
Tequily Profil |
#6 · Zasláno: 30. 10. 2012, 11:00:19
peta:
no, možná pro maximální rychlost to není, to byla špatná formulace Struktura tabulky: id, pocet, cena, idDostupnosti, druheID, datumUpdate Indexy: ID -> mohutnost cca 80000, idDostupnosti -> mohutnost 2 SQL: "UPDATE tabulka SET pocet = $pocet, datumUpdate = NOW() WHERE (id = $nejakeID AND idDostupnosti= 1)" $pocet a $nejakeID získávám z XML, skládám si SQL a ukládám do nového souboru |
||
peta Profil |
Zkousel jsi importovat obsah toho sql souboru pres phpmyadmina? Pripadne zkopirovat tam do zalozky sql ty sql dotazy a kliknout ok?
To vypada totiz, ze 15 minut trva jen to, nez si soubor pripravis a on pak za 0,7s provede jeden dotaz. Takze mas nejspis chybne svuj php kod pro import, ktery to nejspis radek po radku zpracovava a posila do sql a pod. Zkus toho phpmyadmina a import zalozku (nejdriv si tam rozklikas v menu svoji databazi). Take muzes pouzit import z prikazove radky, pokud mas pripraveny soubor s sql dotazy. Schvalne muzes pridat tvuj php import kod, pro zajimavost s kratkou ukazkou (5 radku) ze vstupniho souboru. |
||
Tequily Profil |
#8 · Zasláno: 31. 10. 2012, 16:23:14
peta:
Přes import jsem to zkoušel ;-) taky to nezvládl. Nicméně problém jsem vyřešil. SQL jak předtím, tak nyní, vytvářím foreachem, který projíždí XML. Předtím: foreach($xml->SHOPITEM as $zam) { $sql .= "UPDATE tabulka SET pocet = $pocetKusu, datumUpdate = NOW() WHERE (id = $id AND idDostupnosti= 1);" } Nyní 2 možnosti. Znatelnou změnou také bylo, že jsem NOW() nahradil za $datum = date("Y-m-d") NOW() je totiž další dotaz pro databázi. Sice trvá neznatelně dlouho, ale při vyšším počtu dotazů už se to projeví. Když dosadíme pevnou hodnotu, skript se nám zase o něco zrychlí. 1. možnost pomalejší: $sql = "UPDATE dostupnostKniha SET datumUpdate = '$datum', pocetKusu = CASE id"; foreach($xml->SHOPITEM as $zam) { $sql .= " WHEN '$id' THEN $pocetKusu"; } $sql .= " END WHERE (idDostupnosti = 2)"; Tento sql projíždí všechny záznamy s dostupností 2, což je v pořádku, nicméně může nastat chvíle, kdy dané ID v XML není, tedy i v tomto připadě se zkontroluje. To eliminuji v druhém sql, které používám již všude. 2. možnost, velmi rychlá: $sql = "UPDATE dostupnostKniha SET datumUpdate = '$datum', pocetKusu = CASE id"; foreach($xml->SHOPITEM as $zam) { $sql .= " WHEN '$id' THEN $pocetKusu"; $idcka .= "'$id',"; } $idcka = substr($idcka,0,-1); $sql .= " END WHERE (id IN($idcka) AND idDostupnosti = 2)"; SQL projede pouze záznamy s dostupností 2 a s ID, které si vybírám. Přestože $idcka obsahuje cca 30 000+ idcek (jak které XML, někde je to až 100 000), je to rychleší. Jen pro představu mysqli_query($db, $sql) V druhém případě trvání skriptu bylo cca 5 minut. V posledním, velmi efektivním případě, trvá skript pouhé 3 minuty a to včetně překopírování celého XML (60Mb) na náš server!!!. Pokud tedy někdo budete řešit podobný problém, doporučuji užít metodu WHEN. Děkuji za účast v diskusi a za případné komentáře, návrhy, vylepšení, či dotazy. |
||
Kajman Profil |
#9 · Zasláno: 31. 10. 2012, 21:40:02
Myslím, že budou i rychlejší varinaty, než s case. Zkuste pro zajímavost změřit takto vygenerovaný dotaz
update `dostupnostKniha` join (select 1 id, 10 k union select 2 id, 20 k union select 3 id, 30 k union select 4 id, 40 k) dbtmp on `dostupnostKniha`.id = dbtmp.id and `dostupnostKniha`.idDostupnosti = 2 set `dostupnostKniha`.pocetKusu = dbtmp.k, `dostupnostKniha`.datumUpdate = '$datum' Pokud by bylo příliš řádků, dala by se místo toho poddotazu použít temporary tabulku. Místo case by šly použít i funkce elt a field, ale myslím, že to výrazně rychlejší nebude, jen to trošku zkrátí výsledný dotaz. UPDATE dostupnostKniha SET datumUpdate = '$datum', pocetKusu = Elt(Field(id, 1, 2), 10, 20) WHERE id IN ( 1, 2 ) and idDostupnosti = 2 |
||
peta Profil |
#10 · Zasláno: 2. 11. 2012, 08:24:56
No vida, uz to z nej leze :) V prvnim prispevku nic o NOW ani CASE nebylo.
id = $id AND idDostupnosti= 1 // tu podminku bych dal opacne a key udelal jako (idDostupnosti,id). Dostupnosti odbouras treba pulku idcek a zjednodusis porovnavani. |
||
Časová prodleva: 4 dny
|
|||
Tequily Profil |
peta:
V prvním příspěvku to nebylo, protože CASE tam nebyl žádný :-) Teď jsem ale narazil na problém další. Potřebuji updatovat 3 sloupce naráz a CASE už to nezvládá, nebo nevím jak jej napsat pro více sloupců, vite jak si s tím poradit? $sql = "UPDATE dostupnostKniha SET datumUpdate = '$datum', cena= CASE id $sql1 END, sleva = CASE id $sql2 END, dph = CASE id $sql3"; $sql .= " END WHERE (idDostupnosti = 4 AND id IN($idcka))"; $sql1, $sql2 a $sql3 jsou jsou vygenerované WHEN a jsou v pořádku. |
||
Kajman Profil |
#12 · Zasláno: 6. 11. 2012, 09:09:08
Tequily:
„a CASE už to nezvládá“ Jak konkrétně to nezvládá? Překročíte maximální velikost dotazu? Pak to můžete rozdělit na více updatů. A [#9] jste četl? Verze s poddotazem nebo s temporary tabulkou by mohla být při více sloupcích kratší i rychlejší. |
||
Tequily Profil |
#13 · Zasláno: 6. 11. 2012, 10:40:16
Kajman:
Ano, četl jsem. Řádků je vskutku hodně, takže spíše bych pracoval s temporary tabulkou. S tou jsem ale ještě nepracoval, takže si o tom musím nejdříve něco přečíst a zatím jsem se k tomu nedostal. Rozdělení na více updatů však pomohlo, nevím proč jsem to nezkusil dříve. |
||
Časová prodleva: 11 let
|
0