Proměnná (IP) v názvu tabulky
- dj.kure
- Člen | 70
Ahoj,
dělám logování dostupnosti IP adres a to se mi ukládá v rámci BASHe
do databáze. Každá IP má svou vlastní tabulku (ping_127.0.0.1
jako příklad).
V Nette se snažím získat data z tabulky takto:
$table_check = $this->monitoring->query("SHOW TABLES LIKE 'ping_" . $ip . "'");
return $table_check->getRowCount() > 0 ? $this->monitoring->table("ping_" . $ip) : false;
Problém je v tom, že se mi přeformátuje název tabulky a každý oktet se oddělí tečkou (zde SQL dotaz, který Nette vygeneruje):
SELECT *
FROM `ping_127`.`0`.`0`.`1`
ORDER BY `datum` DESC
LIMIT 20
Zkoušel jsem různé formáty vložení proměnné (i staticky IP napsat), ale vždy mi to takto nešťastně tu IP rozdělí po tečkách. Poradíte mi, prosím, jak mám zajistit správný formát IP? Zkoušel jsem různé uvozovky, zpětné apostrofy, … ale prostě nic :-(
Chápu, že bych mohl nahradit tečky třeba podtržítky, ale tomu bych se rád vyhnul.
Děkuji.
Editoval dj.kure (19. 8. 2021 16:04)
- Marek Bartoš
- Nette Blogger | 1274
Myslím že by sis měl přečíst něco o SQL injection a nechat databázi
vkládat hodnoty do dotazu za tebe.
https://owasp.org/…QL_Injection
https://doc.nette.org/…atabase/core#…
- dj.kure
- Člen | 70
Asi si nerozumíme, já nechci používat klasické „query“, protože dále s daty pracuji (filtrování, limity, řazení)… Pokud použiju query a celý dotaz naformátuji, tak to samozřejmě funguje, ale já potřebuji předat tabulku jako objekt, se kterým se ještě bude dále pracovat. A jestli se nepletu, tak samotné query pozdější věci jako další podmínky (where), limity (limit), řazení (order) atd. neumožňuje.
Samozřejmě by bylo skvělé, kdyby fungovalo něco jako:
return $table_check->getRowCount() > 0 ? $this->monitoring->table("ping_?", $ip) : false;
Ale to nefunguje.
Edit:
Zatím jsem to tedy poskládal přes čisté query, kdy mám vytvořenou
proměnnou filtr a ta se na základě zadaných parametrů (s
mysqli_real_escape_string()
) doplňuje, ale toto řešení se mi
moc z bezpečnostního hlediska nelíbí. Naštěstí se nejedná o veřejnou
aplikaci, takže se z toho nestřílí, ale i tak. Kdyby náhodou někdo
věděl, jakým způsobem ten název tabulky vyřešit, tak bych byl moc
vděčný.
Editoval dj.kure (19. 8. 2021 16:55)
- Kamil Valenta
- Člen | 820
Používat tečky v názvu tabulky nebude moc šťastné a obtížně
přenositelné (tečkami se odděluje databáze, schema, od tabulky).
Pokud bys trval na této cestě, pak raději tečky nahradit třeba za
podtržítka a ukládat do „ping127_0_0_1“.
Ale také se přikláním k názoru, že Ti asi stačí jedna tabulka a v ní sloupec „ip“…
- dj.kure
- Člen | 70
Ahoj, děkuji za odpovědi, opravdu nestačí jedna tabulka. Měl jsem to v jedné tabulce do teď (na Postgresu, správně oindexované, vhodně zvolené datové typy), ale když se do tabulky vkládá záznam každých co 5 vteřin (datum, min/max/avg, packet loss) pro každou IP a těch je z počátku kolem stovky (ale chci to nasadit pro celou síť, takže kolem 4k-6k IP), tak to je 20 insertů za vteřinu, takže nějakých 52 milionů řádků za měsíc a já potřebuji uchovávat alespoň půl roku historie a to už je 311 milionů řádků v jedné tabulce, ze které budu průběžně selektovat do grafů, přes triggery bych rád ještě zajistil, aby se záznam starší půl roku automaticky mazal…, atd. a to už prostě pro tu tabulku je šílený mazec. Když to rozdělím na samostatné tabulky pro každou IP, tak se dostanu výkonově na úplně jinou úroveň.
- dj.kure
- Člen | 70
Tak jsem se rozhoupal a u IP adres jsem nahradil tečky podtržítky (do
čehož se mi tedy úplně nechtělo, ale vidím, že je to nezbytné). Nakonec
to nebyl žádný problém a je vše vyřešeno (v podstatě jeden
$ip_r = str_replace(".", "_", $ip)
a hotovo). Jen tedy škoda, že
se nevyřešil původní problém a zůstává nad tím nevyřešený otazník
(používání proměnné v názvu tabulky).
- uestla
- Backer | 799
Sestavovat název tabulky dynamicky na úrovni databázové vrstvy nepovažuju za šťastný nápad – obzvlášť v momentě, kdy jsi schopen název tabulky sestavit ručně tak, jak popisuješ, ještě před položením dotazu.
V momentě, kdy pak potřebuješ daný název použít (ač v proměnné),
je cestou využít metodu delimite()
na driveru:
$table = sprintf('ping_%s', str_replace('.', '_', $ip));
$connection->query(sprintf('SHOW TABLES LIKE %s', $connection->getDriver()->delimite($table)));
- David Kudera
- Člen | 455
Co použít partitioning v postgresu podle datumu a mít tabulku třeba pro každý měsíc? Ukázka přímo v dokumentaci postgresu: https://www.postgresql.org/…tioning.html)
Pak můžeš zapisovat i číst z jedné hlavní tabulky a postgres si to sám rozhodí do správné tabulky podle nastavené podmínky – tady by to byl rozsah datumů vytvoření.
(..... pokud je tedy opravdu potřeba mít několik tabulek…)
Editoval David Kudera (20. 8. 2021 11:06)
- dj.kure
- Člen | 70
Takže když budu potřebovat vyselectit data za určité období, což bude znamenat třeba překrytí 4 různých datumových tabulek, tak si s tím PGSQL poradí automaticky? Zatím mi tedy samotné rozdělení do tabulek maximálně vyhovuje (jednoduchost a rychlost). I samotné zálohování je jednodušší, protože potřebuji dlouhodoběji zálohovat třeba jen nějaké rozsahy IP.
- David Kudera
- Člen | 455
Přesně tak, Postgre by pak měl koukat jen do těch tabulek, které odpovídají hledanému datumu (range apod.). Zároveň to ale ani nenutí pracovat v aplikaci jen s tou základní tabulkou, klidně můžeš pracovat přímo i s potomky.
No a rozdělit se to dá taky libovolně, nemusí to být striktně jen podle
datumu. Vlastně ani ta podmínka/rozhodovací sloupec není povinný. Klidně
se to dá použít i jen k tomu, aby člověk nemusel definovat schéma všech
tabulek pokaždé znovu. Vytvoří se ta základní a ostatní se pak tvoří
přes CREATE TABLE ping_127_0_0_1 () INHERITS (ping_base);
.
Když už je to ale opravdu potřeba, tak partitioning je nejvíc super i s nějakým tím sloupcem podle kterého pak Postgres hledá ve správné tabulce. No a právě tvůj případ mě osobně přijde jako téměř to stejné, co ukazuje example v Postgres dokumentaci (samozřejmě ale neznám všechny požadavky :-) ).
Editoval David Kudera (20. 8. 2021 15:55)