Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailemVyřešeno SQL dotaz

Zdravím, potřeboval bych optimalizovat SQL dotaz, ale nemám představu jak přesně...

Zadání: Potřebuji z tabulky níže vybrat řádky, které jsou nejnovější k hodnotě key_id, ale přitom daný řádek má status = 1

id	key_id	tstamp		status
----------------------------------
9	1	1412067222	1
8	2	1412067174	2
7	4	1412067126	2
6	4	1412067078	1
5	2	1412067030	2
4	3	1412066982	1
3	2	1412066934	1
2	1	1412066886	2
1	3	1412066838	1

Výstup by pak měl vypadat takto:

id	key_id	tstamp		status
----------------------------------
9	1	1412067222	1
4	3	1412066982	1

Současný dotaz vypadá takto:

SELECT * FROM tabulka as t 
WHERE t.tstamp >= (SELECT max(tstamp) FROM tabulka WHERE key_id	= t.key_id)
AND t.status=1

Jelikož mám v tabulce skoro 500 000 záznamů, tak tento dotaz trvá na mém serveru kolem 4 vteřin.
Děkuji za pomoc

Jsou zobrazeny jen nové odpovědi. Zobrazit všechny
Předmět Autor Datum
Jinak jak už zaznělo, funkci Max bys měl použít nad co nejmenším počtem záznamů, tedy je vhodná maxi…
touchwood 30.09.2014 12:40
touchwood
No ano, na max(tstamp) se ptá dotaz (SELECT max(tstamp) FROM tabulka WHERE key_id = t.key_id) a to j…
lukinpark 30.09.2014 12:47
lukinpark
jenže na ten "průměr" 15 řádků musí databázový stroj projít celý půlmilion řádků (a to tolikrát, kol…
touchwood 30.09.2014 12:50
touchwood
To je pravda, tak jak by tedy měl ten dotaz vypadat lépe? Jde to vůbec?
lukinpark 30.09.2014 12:56
lukinpark
Takhle jsem to lamoidně naklikal v Accessu (psaní selectů není zrovna má silná stránka): SELECT nor…
touchwood 30.09.2014 13:06
touchwood
Díky za snahu, ale bohužel ani toto není ono :-) Výpis z tabulky výše je tento: id key_id tstamp st…
lukinpark 30.09.2014 13:16
lukinpark
v tom případě máš chybu v zadání: vybrat řádky, které jsou nejnovější k hodnotě key_id, ale přitom…
touchwood 30.09.2014 14:07
touchwood
Ano rychlejší to je, ale nevypíše to to, co potřebuji, možná jsem to napsal tak, že se to dá pochopi… nový
lukinpark 30.09.2014 14:13
lukinpark
ne, napsal jsi to tak, že se to dá pochopil jen tím jedním způsobem ;-), tj. vybrat nejnovější řádky… nový
touchwood 30.09.2014 14:17
touchwood
cize ak nejake key_id sa nachadza na 2 a viac riadkoch, ale aspon jedno z nich ma status <> 1, tak u…
wam_Spider007 30.09.2014 14:08
wam_Spider007
to by tam nemohly ale být ani key_id 1 a 3.. nový
touchwood 30.09.2014 14:12
touchwood
Pokud je key_id = 2 a nejnovější status = 2, tak key_id = 2 vůbec nezobrazovat. Zobrazit pouze key_… nový
lukinpark 30.09.2014 14:15
lukinpark
chtěl jsi napsat, že pokud pro dané key_id existuje nejnovější status > 1, tak nevypisovat poslední… nový
touchwood 30.09.2014 14:20
touchwood
Ano, tak jsem to myslel :-) nový
lukinpark 30.09.2014 14:22
lukinpark
Tak v tom případě bych možná navrhnul úpravu databáze přidáním tabulky Status1, kde by v podsatě sta… nový
JR_Ewing 30.09.2014 14:49
JR_Ewing
tak, normalizace většinou řeší tyhle problémy s podivnými a zbytečně složitými selecty. nový
touchwood 30.09.2014 15:39
touchwood
skus takto: create view v_docasne as select key_id, max(tstamp) tstamp from tabulka group by status… nový
wam_Spider007 30.09.2014 14:25
wam_Spider007
Bohužel, prázdný výsledek... nový
lukinpark 30.09.2014 14:37
lukinpark
sry, nema tam byt group by status ale group by key_id ale prazdne by to byt nemalo. nový
wam_Spider007 30.09.2014 14:42
wam_Spider007
Paráda, funguje :-) pecka pecka :-) kleslo to na krásných 0,5vteřin :-) díky nový
lukinpark 30.09.2014 14:55
lukinpark
Presne takýmto spôsobom by som to riešil. Len by som nevytváral view, ale by som to dal rovno do toh… poslední
los 30.09.2014 22:50
los

Jinak jak už zaznělo, funkci Max bys měl použít nad co nejmenším počtem záznamů, tedy je vhodná maximální předfiltrace, protože předpokládám, že "status=1" bude mít mnoho záznamů.

Jinak ještě, pokud záznamy přibývají výlučně na základě časového sledu, tak by nebylo od věci předomezit výběr pomocí SELECT TOP/LAST nad seřazeným id, řekněme 1000 řádek (záleží na tom, jak často se daný jev vyskytuje - toto není univerzální optimalizace!!). Zde pak přijde samozřejmě vhod index nad polem id.

edit: a jinak to vidím tak, že všechny key_id sis měl normalizovat do separátní tabulky, najoinovat a selektovat z ní, nikoli odkazem na celou velkou tabuli.

Takhle jsem to lamoidně naklikal v Accessu (psaní selectů není zrovna má silná stránka):

SELECT normaliz.key_id, Max(tabulka.datestamp) AS MaxOfdatestamp, tabulka.status
FROM normaliz INNER JOIN tabulka ON normaliz.key_id = tabulka.key_id
GROUP BY normaliz.key_id, tabulka.status
HAVING (((tabulka.status)=1));

tabulka "normaliz" obsahuje jen jedno pole, key_id, které funguje jako primární klíč vztahu 1:N vůči tabulce "tabulka" (tahle tabulka se dá samozřejmě generovat dotazem, nebo rovnou udělat jako dotaz)

Pravděpodobně to půjde ještě dále optimalizovat, ale na to jsou tu jiní kabrňáci, rozhodně neaspiruju na titul krále SQL ;-)

Díky za snahu, ale bohužel ani toto není ono :-) Výpis z tabulky výše je tento:

id	key_id	tstamp		status
----------------------------------
9	1	1412067222	1
6	4	1412067078	1
4	3	1412066982	1
3	2	1412066934	1

ale měl by být takový:

id	key_id	tstamp		status
----------------------------------
9	1	1412067222	1
4	3	1412066982	1

chtěl jsi napsat, že pokud pro dané key_id existuje nejnovější status > 1, tak nevypisovat poslední key_id = 1.. ;-)

V tom případě se obávám, že to musíš řešit opravdu iteračně, ale pak bych si nejprve udělal select TOP xxx

edit: leda bys do "having" přidal celý další subselect porovnávající max(stamp) pro status <> 1 menší než timestamp

Tak v tom případě bych možná navrhnul úpravu databáze přidáním tabulky Status1, kde by v podsatě stačil jen jeden sloupec (i když pořadí by tam mohlo být vždy), ve kterém by program při ukládání, respektive aktualizaci statusu z a/nebo na 1 přidával a nebo mazal indexy odpovídající ID v první tabulce. Status by se tedy vůbec nenacházel v první tabulce (paralelne k tomu by mohla být tabulka Status2, kde by zase byly indexy těch ostatních záznamů).

Pak jediné, co by ti stačilo projet indexy (ID) záznamů v tabulce Status1, jestli se jim neschodují key_ID a ty nejnovější vypsat.

skus takto:

create view v_docasne
as
select key_id, max(tstamp) tstamp from tabulka group by status;

select t.id, t.key_id, t.tstamp, t.status
from tabulka t
inner join v_docasne v on v.key_id = t.key_id and v.tstamp = t.tstamp
where t.status = 1;

Zpět do poradny Odpovědět na původní otázku Nahoru