Fórum Root.cz
Hlavní témata => Server => Téma založeno: hknmtt 22. 02. 2025, 16:16:47
-
Riesim situaciu, kedy mam tabulu s id-ckami, kde su dva typy obsahu, a potrebujem jeden z tych typov filtrovat joinom, ale ponechat ten druhy mez zmeny.
Povedzme, ze mam jeden typ stranka a druhy typ clanok, ktory ma kategorie.
Inak povedane, mam tabulku content, kde mam 1:clanok, 2:stranka, 3:clanok, 4:stranka, 5:clanok a potrebujem spravit join na druhu tabulku categories a odfiltrovat clanky, ktore nie su v zozname dodanych kategorii, ale s tym, ze stranky sa zachovaju, kedze sa ich to netyka.
Jednoduche riesenie je spravit right join na categories tabulku, co mi odfiltruje clanky. Lenze right join tym padom zahodi stranky z content tabulky, kvoli absencii zhody na id-cku v tabulke categories. Ak spravim zase left join, tak viem spravit napriklad (category is null or in(..)), cim si odfiltrujem clanky, ktore nie su v zozname katagorii ktore chcem, a ze stranky budu mat NULL, kedze v tej joinutej categories tabulke vobec nie su.
Problem vsak je, ak clanok nema nastavenu ziadnu kategoriu, tak sa vyhodnoti ako is null a ostane v zozname.
Normalne by som mal dve samostatne tabulky a logiku oddelil, lenze tak by som nevedel strankovat obsah ako jeden celok. A nejak neviem ako to vyriesit teraz.
Napada ma asi pouzit nejaku sub-query alebo self join, ale nie som si uplne isty ktore riesenie je spravne.
-
Asi je navhodnejsie pouzit nieco ako:
SELECT id FROM content WHERE type = stranka OR id IN(SELECT id FROM content RIGHT JOIN categories USING(id) WHERE categories.category = X) ORDER BY id ASC
Akurat neviem aky to bude mat dopad na vykon.
-
SELECT co.id FROM content co
LEFT JOIN categories ca ON co.categoryId = ca.id
WHERE ca.id IS NOT NULL
OR co.type = 'stranka'
Tohle by mělo zachovat všechny záznamy content, co mají typ 'stranka' bez ohledu na cokoliv dalšího + záznamy content, co mají jiný typ než 'stranka' a mají categoryId vyskytující se v category.
Nebo jsem špatně pochopil požadavek?
-
SELECT co.id FROM content co
LEFT JOIN categories ca ON co.categoryId = ca.id
WHERE ca.id IS NOT NULL
OR co.type = 'stranka'
Tohle by mělo zachovat všechny záznamy content, co mají typ 'stranka' bez ohledu na cokoliv dalšího + záznamy content, co mají jiný typ než 'stranka' a mají categoryId vyskytující se v category.
Nebo jsem špatně pochopil požadavek?
Diky, mal som uz funkcnu verziu, ale toto ma inspirovalo ju znacne zjednodusit.
-
SELECT co.id FROM content co
LEFT JOIN categories ca ON co.categoryId = ca.id
WHERE ca.id IS NOT NULL
OR co.type = 'stranka'
Tohle by mělo zachovat všechny záznamy content, co mají typ 'stranka' bez ohledu na cokoliv dalšího + záznamy content, co mají jiný typ než 'stranka' a mají categoryId vyskytující se v category.
Nebo jsem špatně pochopil požadavek?
Diky, mal som uz funkcnu verziu, ale toto ma inspirovalo ju znacne zjednodusit.
Podmínky s OR mohou mít problémy s výkonem - záleží jaká jsou data, jak máte indexy i jakou máte databázi (a jakou verzi). Samozřejmě, že záleží i na velikosti dat a intenzitě provozu. V některých (dnes spíš hraničních) případech je nutné dotaz přepsat na UNION.
-
Podmínky s OR mohou mít problémy s výkonem - záleží jaká jsou data, jak máte indexy i jakou máte databázi (a jakou verzi). Samozřejmě, že záleží i na velikosti dat a intenzitě provozu. V některých (dnes spíš hraničních) případech je nutné dotaz přepsat na UNION.
To se ještě dneska vážně používají databáze, které tyto sémanticky shodné zápisy (s OR nebo s UNION) nedokáží převádět automaticky (podle toho co je pro ně výhodnější na provedení) a nutí k tomu programátora?
-
Podmínky s OR mohou mít problémy s výkonem - záleží jaká jsou data, jak máte indexy i jakou máte databázi (a jakou verzi). Samozřejmě, že záleží i na velikosti dat a intenzitě provozu. V některých (dnes spíš hraničních) případech je nutné dotaz přepsat na UNION.
To se ještě dneska vážně používají databáze, které tyto sémanticky shodné zápisy (s OR nebo s UNION) nedokáží převádět automaticky (podle toho co je pro ně výhodnější na provedení) a nutí k tomu programátora?
Jsou takové databáze a hodně se používají. PostgreSQL to nedělá 100%, MySQL a MariaDB pravděpodobně také ne. U Postgresu není problém v transformaci (transformace by se ani dělat nemusela, jde o podobu finálního plánu) - takový patch už byl vytvořený, a měl pár stovek řádek, ale v rozhodnutí, kterou cestu preferovat - jestli bitmap indexscan nebo merge index scanu nebo ještě něco jiného. U výrazů s OR jsou větší problémy s odhady, a kvalita odhadu je základ.
-
To se ještě dneska vážně používají databáze,...
Ony se pouzvaji databaze, ktery ti klidne pro jedno query vygenerujou 20 ruznych exekucnich planu. Z toho jeden bude ten (semi)idealni a 2-3 budou zcela katastrofalni. Ten zbytek bude nekde mezi.
A forma zapisu(mimo jine) kupodivu vede na to, ze ta databaze generuje lepsi plan.
I v tomhle jednoduchym pripade se ti muze stat (a zcela jiste obcas stane) ze to probehne tak, ze se nejdriv udela ten join pres vsechny zaznamy a teprve pak se to bude filtrovat. A kdyz tech zaznamu bude hodne .... bude klidne i radove vykonejsi ten union.