Hello!
Van egy kis problemank. Adott egy ~10 GB-s adatbazisunk (nem sajat), amin vegig kellene futni, es kidumpolni egy fileba azoknak az oszlopoknak a neveit, amelyekben nincs mas adat, csak NULL, 0 vagy '', tehat nem hasznaljak. Utana a filebol kiolvasva egy masik scripttel ALTER TABLE var1 DROP COLUMN var2-t vegrehajtani mindegyiken. Az se lenne talan gond, ha egyenesen dropolnank, de jo lenne, ha az is meg lenne, mit dobunk ki belole. Nincs indexeles, van vagy 2 000 000 sor meg 4000 oszlop. Nemelyik tablan akar 50-70 masodpercig is eltart egy query.
Valakinek valami otlet, hogy lehetne megoldani?
- 2482 megtekintés
Hozzászólások
Milyen dbms-ben van ez, mert ettől nagyban függ a megoldás.
- A hozzászóláshoz be kell jelentkezni
Ja elfelejtettem konkretumokat irni, sorry. MySQL InnoDB engine-el.
- A hozzászóláshoz be kell jelentkezni
Egyszerű megoldás, ha írsz egy PHP, Python, Perl, Ruby vagy hasonló nyelven egy szkriptet, ami SELECT * FROM TablaNev -et nyom minden táblára, és soronként minden mezőre megnézi, hogy az 0, NULL vagy ''-e. ha egy mező minden sorban ilyen értékű, akkor kiírja a mező (oszlop) nevét (vagy sorszámát). Ennek a szkriptnek a kimenetéből már lehet generálni néhány ALTER TABLE TablaNev DROP COLUMN OszlopNev parancsot, amit már le lehet futtatni.
Lehet, hogy ez a külső szkript túl lassú lesz 10 GB adatra. Ha így van, akkor írhatsz néhány tárolt eljárást (stored procedure), amely közvetlenül a MySQL szerveren fut. Nem tudom, hányszor gyorsabb a tárolt eljárás a külső szkriptnél, a szorzó 0.5 és 100 között akárhol lehet.
- A hozzászóláshoz be kell jelentkezni
visszaadnám a diplomám, ha erre select * lenne a megoldás...
minden oszlopra adj ki scriptből egy select distinct oszlopnev utasítást, és számold meg, mennyi a végeredmény. Ha egy és az olyan, ami szerinted nem kell, akkor dobd el az oszlopot.
- A hozzászóláshoz be kell jelentkezni
mert miert nem jo a select *? raer nem? ha ket orat fut ket orat fut..
- A hozzászóláshoz be kell jelentkezni
mert amit kiköp, azt utána még fel kell dolgozni és nem mindegy, hogy 5 sor vagy 2 millió. Nem csak az az idő, amíg a mysql összevadássza diszkről az adatot, az is idő, míg áttolja a kliensnek.
- A hozzászóláshoz be kell jelentkezni
Minden oszlopra külön futtatni egy query-t ami ellenőrzi amit kell, lehetőleg COUNT vagy hasonlót használni.
Ahol N = 0 ott lehet törlésre jelölni az oszlopot és előtte persze lementeni egy archiv db táblájába.
- A hozzászóláshoz be kell jelentkezni
tutti?:)
közben javítottad:)
- A hozzászóláshoz be kell jelentkezni
Igen, késő van már. :D
- A hozzászóláshoz be kell jelentkezni
A COUNT nem jo InnoDB eseten, mert lassu. En valami olyasmivel probalkoznek, hogy:
function cleandb($db) {
$res = mysql_query("SELECT TABLE_NAME AS table, COLUMN_NAME AS column FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = '$db'");
while ($row = mysql_fetch_object($res)) {
$exists = mysql_fetch_assoc(db_query("SELECT 1 FROM {$row->table} WHERE {$row->column} IS NOT NULL AND $column <> 0 AND $column <> ''"));
if (!array_shift($exists)) {
db_query("ALTER TABLE $table DROP COLUMN $column");
}
}
}
- A hozzászóláshoz be kell jelentkezni
Érdemes megmérni, hogy a SELECT * vagy a SELECT DISTINCT OszlopNev a gyorsabb. A bemenettől függően akármelyik is lehet a gyorsabb. A SELECT DISTINCT OszlopNev végigolvassa a táblafájlt minden oszlopra. Ha 100 oszlop van, akkor 100-szor olvassa végig, ami lassabb lehet a SELECT *-nál.
- A hozzászóláshoz be kell jelentkezni
oké, a nézeteltérés oka az, hogy bennem fel sem merült, hogy valaki egy két millió soros táblát egyben kikérjen a mysql-től és azt beleborítsa egy scriptbe.
Abban igazad van, hogyha egyszer futtatod le a select *-ot, az látatlanban gyorsabb lesz, mint minden mezőre külön egy distinct.
Viszont akkor sokkal több időd elmegy arra, hogy írj egy scriptet, ami minden mezőt párhuzamosan kotorászik végig, hogy mi van benne. A fejlesztés, debuggolás, futtatás valószínűleg több időt fog elvinni, mintha írsz egy kőegyszerű scriptet és feleslegesen megdaráltatod egy kicsit a mysql-t.
- A hozzászóláshoz be kell jelentkezni
C#-ban kb. 1-1.5 órás meló lenne összedobni a logikát. Lehet nagyon erőforrás barátra írni, memória igénye nulla, procsszor igénye szintén kevés. Az idő 90%-a kb. egy menetben való adatok felolvasásának IO igénye lenne.
Ráadásul indexek sincsenek, ami szintén érv a teljes felolvasás mellett.)(Az egész db-t csak egyszer kell felolvasni.)
- A hozzászóláshoz be kell jelentkezni
Ez valoban elkepzelheto.
Plusz gyorsitas (legalabbis a DB->script IO igenyen), ha eloszor lekered select *-gal mondjuk az elso 1000 sort (vagy valamennyit, ami elenyeszo a teljes DB-hez kepest), es rogton kiszorod azokat az oszlopokat, amik biztosan kellenek. Utana a select mar nem a teljes DB-n futna, hanem csak a gyanusan ures oszlopokra.
PHP-ban van mar nehany DB piszkalo scriptem, az 1 ora jo felso becsles fejlesztesi idore, de inkabb nehanyszor 10 perc. Ekkora DB-re nagyjabol a futasidovel osszemerheto, utana 1 ejszaka alatt mindenkeppen lefut (az alterrel egyutt).
Ha konnyen programozhato DB (eddig csak Postgreshez irtam tarolt eljarasokat), akkor valoszinuleg megsporolhato a fejlesztesi es a futasido nagy resze. De egy egyszerhasznalatos kodra nem erdemes uj nyelvet tanulni.
--
Auto correct can go straight to He'll.
- A hozzászóláshoz be kell jelentkezni
+1, tetszik, igy csinaljuk :)
- A hozzászóláshoz be kell jelentkezni
2 millio sor nem olyan sok, gyorsan végig lehet rajta iterálni. 4000 oszlopra egyenként distinctet adni, azt én húzósabbnak látom, a futási idő még csak nem is becsülhető.
- A hozzászóláshoz be kell jelentkezni
Azt nem tudom a MySQL mit csinal, de egy par DBMS igen furan kezeli a NULL ertekeket, ezert a distict, es az aggregat fuggvenyek nem feltetlenul adnak jo valaszt.
Szerintem sincs egyszerubb megoldas, mint tenyleg soronkent vegignezni.
Igazabol, azt sem tudom mit varsz egy ilyen "clean-up"-tol, szerintem az esetlegesen felszabadulo hely miatt nem eri meg, es valoszinuleg gyorsabb sem lesz az adatbazis tole. Akkor meg minek?
- A hozzászóláshoz be kell jelentkezni
uj adatbazist fogunk tervezni a meglevo helyett, es annyira atlathatatlan az egesz szar, hogy ugy dontottunk, lepusztitjuk a cuccot olyan szintre, ami talan meg ertelmezheto, mert legalabb a randomadatok nem lesznek benne.
- A hozzászóláshoz be kell jelentkezni
meg van egyebkent, csinaltunk egy stored procedure-t, ami a parameterkent megkapott tablanev alapjan kidobalja a felesleges cuccokat, csak meg nem futtattuk le, mert bugos, azt holnap javitjuk :D
- A hozzászóláshoz be kell jelentkezni
irtam egy shell sciptet, ami mysql-bol lekeri a tablakat, bedumpolja egy fileba, atirja SQL syntaxre, hogy hivja meg a stored procedure-t az adott parameterekkel, aztan lefuttatja azt is, az is ledumpolodik egy fileba, aztan vegrehajtja a dropokat. termeszetesen torlodnek a felesleges fileok, es egy masik fileba kiirja az uptimeot az elejen es a vegen. Szoval lehet tippelni, mikorra fejezi be :)
- A hozzászóláshoz be kell jelentkezni
1d 6h 18m
--
falura elmegy, városban meg úgy sem nézik...
- A hozzászóláshoz be kell jelentkezni
10 ora utan meghalt, mert benne hagytam egy viewt veletlenul, amit csak datamininghoz hasznaltam, es azt nem tudta lekezelni. Szoval igen, a fejleszto is lehet neha hulye user. :D
- A hozzászóláshoz be kell jelentkezni
mint kiderult, 10 ora alatt siman megcsinalta a vegigjarast, csak eldobalasnal volt problema. keszult egy uj verzio, mert bugos volt a regi (tervezesi hiba, olyan dolgokat is eldobott, amit nem kellett volna), es leoptimalizaltuk. 35 perc alatt lefutott :)
- A hozzászóláshoz be kell jelentkezni
miert nem tesztek fel indexet? par ora alatt (najo, ejjel) letrejon, majd bazigyorsan le tudtok kerdezgetni.
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
- A hozzászóláshoz be kell jelentkezni
Szerintem egy tárolt eljárással lehetne legegyszerübben. MySQL-ben nem igazán vagyok otthon, de Oracle alatt tuti így csinálnám.
logikája:
ciklus oszloponként
select count(oszlopnév) ha érték nem 0 vagy NULL
ha count(oszlopnév nulla) oszlop törlése
ciklus vége
pénteken mentés, hétvégére ráengeded, hétfőn vagy örülsz vagy visszatöltessz...
--
Kis problémából egy kis munkával nagy problémát lehet gyártani. Ha valami müxik ne b***tasd :)
Uriember az, aki nem beszél a Windows-ról, pedig tudna...
- A hozzászóláshoz be kell jelentkezni
igen, jo otlet, de index nelkul ugyanugy lassu lesz utana a tablaeleres...
az hogy 10rol leesik 9.5re a giga, attol meg lassan fog vegigcsiszatolni a full table scan.
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
- A hozzászóláshoz be kell jelentkezni
Igaz, bár azt irta újratervezik az adatbázist, akkor vélhetően normalizálnak is kicsit. A teljes beolvasás mint módszer itt szerintem nem érdemes, csak feleslegesen bonyolítaná a dolgot, mert valamilyen nyelven irt logika kellene hozzá, ami már eleve sebességcsökkenés, hibalehetőség stb. Amúgy erre a logika:
logikai tipusú tömb, oszlopszám elemmel, init értékek hamisak
Ciklus végig a táblán
Belső ciklus a mezőkön, ha adott mező értéke nem 0 vagy NULL tömb adott elemét igazra állítjuk
ciklus vége
ciklus vége
ciklus a tömb elemein, ha az érték hamis adott oszlopot törölni
Tárolt eljárással pár sorból egyszerűen és tisztán megoldható. Adatmanipulációt érdemes mindig tárolt eljáráson/triggeren keresztül megoldani, biztosabb és átláthtóbb
--
Kis problémából egy kis munkával nagy problémát lehet gyártani. Ha valami müxik ne b***tasd :)
Uriember az, aki nem beszél a Windows-ról, pedig tudna...
- A hozzászóláshoz be kell jelentkezni
Igen, ujratervezzuk az egeszet, csak arra kell az egesz cucc, hogy atlassuk ezt az egesz szart, mert eles db-t nem latjuk, csak egy masolatunk van. A cucc egyebkent MSSQL volt, es ASP.NET, mi PHP+MySQL-t irunk helyette. Nem tudom, kik voltak ezek a barmok, akik ezt terveztek, de szerintem le kellene loni oket egy desert eagle-vel.
- A hozzászóláshoz be kell jelentkezni
+ UPDATE:
Az oszlop lekérdezésénél order by desc...különben kimaradnak oszlopok
--
Kis problémából egy kis munkával nagy problémát lehet gyártani. Ha valami müxik ne b***tasd :)
Uriember az, aki nem beszél a Windows-ról, pedig tudna...
- A hozzászóláshoz be kell jelentkezni
+1
- A hozzászóláshoz be kell jelentkezni
Azt esetleg lehet tudni, hogy mire használták ezt a táblát? :-)
Abból következtetve, hogy MySQL, nem lehet valami "enterprise" alkalmazás, vagyis a vas, amin fut, sem lehet egy erőgép, vagyis egy-egy lekérdezés eddig is iszonyat ideig tarthatott. Illetve akkor feltételezem, hogy ebbe a táblába csak insertáltak ( lehet, hogy azért nincs index sem ).
Én mindenesetre kipróbálnám azt, hogy mennyi idő az, hogy felrakok indexet 5 oszlopra és aztán mennyi idő alatt fut le az 5 select. Azt kellene megnézni, hogy ez gyorsabb-e, mint index nélkül a select.
A fájlba kidumpolással nem próbálkoznék, szerintem a mySQL gárdája gyorsabb lekérdező algoritmust ír, mint te fogsz :-) ( bár index nélkül, ki tudja... ).
- A hozzászóláshoz be kell jelentkezni
Én mindenesetre kipróbálnám azt, hogy mennyi idő az, hogy felrakok indexet 5 oszlopra és aztán mennyi idő alatt fut le az 5 select. Azt kellene megnézni, hogy ez gyorsabb-e, mint index nélkül a select.
mondjuk hozza kell tenni, hogy az index az a random select-ektol sem ved, tehat ugy is tud relative latvanyosan lassu lenni sok egymas utani select hogyha indexelve van es a tabla relative nagy (nem fer bele a memoriaba/cache-be). de ettol fuggetlenul persze kvazi muszaj, mert igy meg a szekvencialis select-ek is lassuak lesznek.
- A hozzászóláshoz be kell jelentkezni
0. Ellenőrizd le, hogy nem MRG csinálta az eredeti db-t. Ha igen, válts céget.
1. Gyűjtsd össze, hogy milyen adatokra van szükséged.
2. Tervezd meg az új adatbázisodat.
3. Csinálj adatátemelő scripteket.
4. Teszteld az átemelő scripteket ~100 rekordon
5. Tervezz ellenőrző algoritmusokat, amik az átemelést csekkolják.
6. Emeld át az adatokat + teszteld az átemelés helyességét.
- A hozzászóláshoz be kell jelentkezni
MRG?
--
"SzAM-7 -es, tudjátok amivel a Mirage-okat szokták lelőni" - Robi.
- A hozzászóláshoz be kell jelentkezni
Szia,
Írták a select * dolgot, ne!
Írták a distinct-et, ne!
Írták a select count(*)-ot, ne!
Kell egy egyszerű script vagy program, ami a következő-t csinálja
külső ciklus: show tables;ennek az eredményén fogsz végigmenni a belső ciklussal. Hogy tömbbe rakod, vagy magát a result-ot használod részletkérdés
belső ciklus: show columns from XXX, ahol a XXX a tábla neve a belső ciklusból. Ezeken a mezőkön fogsz végigmenni a query-vel
query: select count(YYY) from XXX where YYY is not null and YYY <> '' and YYY <> 0
Ha itt nullát kapsz, akkor ez egy törölhető oszlop, akár itt is mehet az alter table drop column, vagy kiiratod, h tábla-mező törölhető.
Ha nem nulla, akkor van benne érték.
Ez most csak fejből meló mellett pár perc alatt, tesztelni nincs időm, h jó-e.
x
szerk.: ha nem egy, hanem több adatbázis is van, akkor kell még egy legkülső ciklus is, show databases, esetleg show databases like...
- A hozzászóláshoz be kell jelentkezni
A stored procedure is kb. ezt csinalja, csak nem kell reconnectelni allandoan. Nem gyorsabb a tarolt eljaras?
- A hozzászóláshoz be kell jelentkezni
SP-t kicsit bonyolultabb hegeszteni, másrészt meg azt én a gyakran használt funkciókra használom, ezt a vackot pedig egyszer kell helyre tenni imho.
A sebességkülöngség szerintem minimális, a dbms dolgozik az indexeletlen vackon, az adatátvitel meg minimális. Meg kiirathatod, hogy ezt csinálom, itt tartok, aztán látod, h fut a csík :)
A reconnect szintén nem nagyon lesz, legalábbis én még nem tapasztaltam, h hosszú query-k esetén bontaná a kapcsolatot a vas.
- A hozzászóláshoz be kell jelentkezni
Hmm vegulis igazad van. De a stored procedure mar elkeszult, mar csak picit kell rajta hegeszteni, hogy ugy mukodjon, ahogy Nyosigomboc irta.
- A hozzászóláshoz be kell jelentkezni