Autor Zpráva
nethor
Profil
Zdravím,
mám tabulku:

CREATE TABLE `vzdalenosti_obci` (
  `ObecKod1` mediumint(6) NOT NULL,
  `ObecKod2` mediumint(6) NOT NULL,
  `X` mediumint(6) DEFAULT NULL,
  `Y` mediumint(6) DEFAULT NULL,
  `Distance` mediumint(6) DEFAULT NULL,
  UNIQUE KEY `IdObec1_IdObec2` (`ObecKod1`,`ObecKod2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_czech_ci;

, která obsahu je vzdálenosti obcí a vektor směru (X,Y),
je v ní 39 156 306 řádků,
čísla max 6 místná,
ObecKod1, ObecKod2 a Distance pouze kladná.
Překvapil mě obejem dat: 626 500 896 (nevím přesně čeho, Adminer to nepíše, asi Bytes), ale je poměrně velká.

Jde nějakou optimalizací její velikost na disku zmenšit?
juriad
Profil
Každé číslo se ukládá jako 3 byty. Pokud ti nestačí rozsah do 65535 (2 byty), tak 3 byty potřebuješ.

Samotná data (5*3 byty na záznam) tvoří 587 344 590 bytů na disku, to znamená, že MySQL režije je 39 156 306 bytů. Zdá se to hodně? To je přesně 1B na řádek, který MySQL potřebuje nad rámec tvých dat. (Vynásob si 5*3+1 počtem záznamů a dostaneš objem z Admineru.)
Změna jednoho sloupce z mediumint na smallint způsobí ušetření právě těch 39 MB.

Mimochodem, unikátní index potřebuje alespoň 234 937 836 bytů (2*3 bytů na záznam), z čehož vyplývá, že určitě započtený není. Index také bude mít nějakou režii, která nebude zanedbatelná. Pokud ten index nepotřebuješ, zruš jej a nahraď jej jedno-sloupcovým.

Můžeš zkusit kompresi, pokud ti stačí read-only tabulka (dev.mysql.com/doc/refman/8.0/en/myisampack.html, blog-en.openalfa.com/how-to-compress-myisam-tables-in-mysql), ale nedoufal bych v lepší výsledek, jelikož se jedná o čísla a ta asi budou náhodně distribuovaná.

Potřebuješ všechny záznamy z té tabulky, nelze je vypočítat z menší tabulky? Jak často jsou x, y, distance nevyplněné?
Kajman
Profil
Tipuji, že ta tabulka vznikla optimalizací rychlosti výpočtů. Jsou totiž dvě krajní optimalizace

- mít uložené polygony měst a vzdálenost a vektor vypočítat - nízké nároky na disk, vyšší na výkon procesoru
- mít všechno předpočítané - malé nároky na výkon procesoru (pokud jsou správně indexy), obrovské nároky na disk

Do výběru často zasáhne cena procesorového výkonu vs cena disku. Disk je většinou levnější (ale zase může prodražit zálohy atp.).

Pak je ještě možnost to zkombinovat a ukládat si do tabulky výpočty, co již někdo chtěl, tedy takovou cache (co se může průběžně i čistit). Když by to tam nebylo, tak se udělá druhý dotaz, který to spočítá a do cache přidá.

Když máte vzdálenost bodu 1 a 2, tak máte uložené dva řádky, nebo jeden a vektor si otočíte, když hledáte kombinaci 2 a 1?
Keeehi
Profil
Kajman:
Počet obcí v ČR je cca 6250. 6250 na druhou je 39 062 500 takže bych řekl, že tam má uložené dvakrát. Jak 1 => 2 tak i 2 => 1.
nethor
Profil
Tajně jsem doufal, že by MySql mohla mít nějaký nástroji o kterém nevím, ta komprese je tomu blízko.
(Podobně, jako jsem dříve netušil, že jde pomocí SQL provádět náročné výpočty diamerálně rychleji, než přesPHP.)

Je pravda, že jsou v tabulce data svým způsobem duplicitně (i mě to napadlo), tak bych se mohl dostat na polovinu,
ale nyní se s ní v PHP zachází pohodlněji. ...až na tu velikost

Výsledky potřebuji řadit často podle vzdálenosti, obávám se, že výpočet až při dotazu by hodně brzdil.

Díky všem za reakce.
Keeehi
Profil
nethor:
nyní se s ní v PHP zachází pohodlněji. ...až na tu velikost
To je přesně to, o čem psal Kajman. Jednoduchost a rychlost bývá vykoupena nároky na paměť.

obávám se, že výpočet až při dotazu by hodně brzdil.
Tak si udělej test. Myslím, že by to neměl být takový problém. Před mnoha roky jsem to sám zkoušel a běhalo to v pohodě. Pokud si správně vzpomínám tak jsem měl v databázi 10 000 000 GPS souřadnic a řádil jsem je podle vzdálenosti od nějakého bodu, která se počítala až při dotazu. Výsledek si přesně nepamatuji, ale vím že rychlost byla v řádech milisekund. Vzhledem k tomu že výkon dnešních strojů několikanásobně stoupl a že ty těch bodů nemáš deset milionů ale jen šest tisíc, odhaduji, že by s tím neměl být žádný velký problém.
nethor
Profil
Keeehi
Teda já žasnu, ono to skutečně běhá fofrem i s výpočtem. DĚKUJI VELMI!
Zřejmě jsem s předvypočtenou tabulkou čekal problémy, tam, kde nejsou.

Ještě prosím poraďte, co je špatně na dotazu:
select * , (sqrt( pow(-687178 - X , 2) + pow(-966919 - Y , 2) ) * 0.9997) as Distance from 2019lexikonobci where Distance <= 50000 Order By Distance Limit 10000 .
(Err: Unknown column 'Distance' in 'where clause')

resp. jak ho přepsat, abych nemusel opakovat vzorec ve Where klauzuli:
select * , (sqrt( pow(-687178 - X , 2) + pow(-966919 - Y , 2) ) * 0.9997) as Distance from 2019lexikonobci where Distance <= 50000 Order By (sqrt( pow(-687178 - X , 2) + pow(-966919 - Y , 2) ) * 0.9997) Limit 10000 .

Určitě to jde elegantněji...
lionel messi
Profil
nethor:
Ještě prosím poraďte, co je špatně na dotazu:

SQL dotazy sa vyhodnocujú v istom poradí. Vo WHERE sa nedá použiť alias z toho dôvodu, že najprv sa vyhodnotí podmienka (WHERE), až potom sa vykoná vytvorenie aliasov, čiže v tom čase aliasy de facto neexistujú.

V MySQL existujú najmenej dve možnosti, ako sa s tým vysporiadať:

• Použiť HAVING namiesto WHERE (nevýhoda: pokiaľ viem nejde o prenositeľné riešenie naprieč inými databázovými servermi):

select * , (sqrt( pow(-687178 - X , 2) + pow(-966919 - Y , 2) ) * 0.9997) as Distance from 2019lexikonobci having Distance <= 50000 Order By Distance Limit 10000 

• Použiť poddotaz a nechať WHERE nedotknuté:
select * 
from (select *, (sqrt( pow(-687178 - X , 2) + pow(-966919 - Y , 2) ) * 0.9997) as Distance from 2019lexikonobci) as poddotaz where Distance <= 50000 Order By Distance Limit 10000 

Netuším, čo je rýchlejšie, ani či existuje iná možnosť.
nethor
Profil
lionel messi:
having běhá v pohodě rychle, děkuju.
poddotaz jsem nezkoušel, ... už mi jde z toho hlava kolem... díky.

Vaše odpověď

Mohlo by se hodit


Prosím používejte diakritiku a interpunkci.

Ochrana proti spamu. Napište prosím číslo dvě-sta čtyřicet-sedm:

0