|
Mul on vaja lahendada ülesanne, mis on veidi sarnane pangakonto väljavõtte küsimisega - vaja on kuvada ühe kontoga tehtud tehingud mingil perioodil ja algsaldo perioodi alguses ning lõppsaldo perioodi lõpus. Need kaks viimast on just komistuskiviks. Esialgu lahendasin probleemi nii, et iga tehingu juures säilitatakse ka saldo pärast selle tehingu toimumist. Mõte oli umbes selline, et kui teen andmebaasist päringu perioodil toimunud tehingute kohta, siis täiendavat päringut saldode jaoks pole vaja teha - lõppsaldo saan viimasest tehingust ja algsaldo esimesest tehingust miinus tehingu summa. Esimene probleem oli see, et kui perioodil ei toimunud ühtegi tehingut, aga enne perioodi toimus, siis tuli algsaldode leidmiseks eraldi päring teha. OK, pole hullu. Keerulisemaks läks aga siis, kui selgus et üsna tihti muudetakse vanu tehinguid, mille tulemusena tuleb hulk hilisemaid saldosid ümber arvutada. Saldode ümberarvutamised tõmbasid andmebaasi serveri kooma ja tekitasid Postgresis hulga surnud kirjeid, mida ta siis hoolega vacuumima hakkas. Ma olin eeldanud, et seda juhtub veidi harvemini ning et ümberarvutus pole nii kallis. Nüüd on küsimus kuidas olukorda parandada:
Mulle iseenesest meeldib see teine lahendus, kuna see on hästi lihtne teostada ja kuigi on potentsiaalselt aeglasem kui esimene, siis lähimineviku kohta käivad päringud on kiired ja see ongi oluline. Samuti on lihtne mingi bugi tõttu viga saanud saldosid üle arvutada. Esimese lahendusega on mul see probleem, et programmis pole selget kuu lõpetamise operatsiooni, kuhu antud saldode arvutamist panna. Aasta lõpetamine küll on, aga see ei pruugi anda piisavat efekti. Oleks huvitav teada, mis lahendusi veel välja pakutakse? |
See ongi probleem, mis tuleb lahendada. Ma ei ole kunagi näinud raamatupidajat kustutuskummiga päevaraamatu kallal toimetamas. Rmp printsiibid on paika loksunud juba ammu enne arvutite leiutamist ja seal on omad põhjused. See, et andmebaasis on lihtne UPDATE päringuid teha ei muuda asja. Rusikareegel: sisestatud tehingud on "kivisse raiutud" nende majanduslikku sisu puudutavas osas. Ehk siis mingeid tehnilisi meta-andmeid võib muuta, aga näiteks tehingusumma on fikseeritud. Osad väidavad, et on ka tehinguid millel puudub majanduslik sisu - näiteks eksikombel sisestatud andmeid. Ma seda erisust ei näe - raamatupidamise rakendus peab suvalisel ajahetkel kõik "ausalt ära rääkima", kui keegi sisestas mingit jama, siis see on ümberlükkamatu fakt. Kui see jama ei oma majanduslikku sisu selle sisestaja jaoks, on tihti mõistlik eeldada, et mingi teine osapool on nende andmetega juba "toimetanud". Kaasus 1. Imporditud 3000 rida on täielik jama? Sisestada miinusmärgiga kanne "3000 rea tühistamine" Importida uuesti Kaasus 2. Keegi tahab muuta tehingusummat. Stop! Sellist võimalust ei ole ju olemas!? Kaks varianti:
Täiesti eraldi küsimus on juba see, et rakendusega töötavad inimesed ei taha igapäevaselt näiteks neid tuhandeid vigaselt imporditud ridu vahtida. See aga ei eelda seda, et me need read andmebaasist peaks minema pühkima. Või "muudetud" arved andmebaasis reaalselt ära muutma. Küsimus on puhtalt vaate tasandil - saraselt näiteks kedagi ei huvita üldse laekumised või keegi töötab ainult mingi konkreetse kliendiga. Tõenäoliselt peab iga rmp süsteem olema nagunii suuteline selliseid väljavõtteid koostama (koos vastavate alg- ja lõppsaldodega). Selles on point täiesti olemas, aga kui vaadata teise nurga alt - kas me peaksime paberil esinevad piirangud IT-süsteemidesse kaasa tooma? Paberil on raske "kogemata" 20 lehte täis kirjutada. Kannete tühistamist/kustutamist lubatakse meie süsteemis kasutajaõigustega, see on ainult administraatoril eriolukordade jaoks. Probleem ei olegi niiväga selles, et midagi muutus, vaid inimesed oma oskamatusest susserdasid programmis midagi kokku ja ei oska sellest olukorrast enam välja tulla. Nad tahaksid alustada puhtalt lehelt, aga jooksev kande number on juba üle 1000 kerinud asi ei ole enam "ilus".
(Jan 29 '10 at 08:33)
Tambet Matiisen ♦♦
1
Jah, selles kontekstis on tark vanu piiranguid säilitada -- need piirangud ei tule paberist kui meediumist vaid raamatupidamisest kui distsipliinist. Armuaja-lahendus on kompromiss: ühest küljest lubab hädakorral viimaseid kandeid näppida, teisest küljest tagab, et "viimaseid kandeid" ei ole kunagi väga palju. Kui Sa saad eeldada, et 20 aasta saldosid kunagi ümber ei rehkendata, on lahendusevalik laiem. Teistpidi ka: kannete mudimise toetamiseks peaksid Sa hakkama ise uut audit trail'i implementima. Aga hea raamatupidamistava on selle probleemi miinuskannete süsteemitsi juba lahendanud.
(Jan 30 '10 at 08:58)
dig
1
Tegemist ei ole mitte "paberist" piiranguga, vaid finantssüsteemide hea tavaga - olemasolevaid kandeid EI muudeta. Muu hulgas tähendab see muutmise võimalus ju seda, et eelnevate perioodide kannete ekspordid (paberil, teistes süsteemides) muutuvad ebausaldusväärseks. Ja probleeme on veel, nii mõnigi on siin juba eelnevalt välja toodud. Teiste sõnadega, see sinu nõue et saaks suvalist tehingut tagant järele, igavesest ajast igavesti muuta, on asi, mis varem või hiljem tuleb ja "hammustab sind tagumikust". Ühel või teisel moel.
(Jan 31 '10 at 09:16)
Anti Veeranna
Raamatupidamissüsteemidesse jooksevad kokku ju kanded väga mitmetest erinevatest infosüsteemidest. Näiteks müügiinfosüsteem või palgainfosüsteem. Neid kandeid tekitatakse sinna kuidagi automaatselt ekspordi/impordi teel. Kuidas on teised lahendanud selle probleemi, et detsembris avastatakse, et veebruaris imporditud 2000 kannet on valed ja need tuleks uuesti importida? Ma ei tahaks uskuda, et tehakse käsitsi 2000 miinuskannet.
(Jan 31 '10 at 15:00)
Tambet Matiisen ♦♦
Esiteks, kontrollid kanded impordi järel üle. Hakatuseks võid nende arvu, kogusumma, kontode arvu ja muu lihtsa statistika nii enne kui pärast importi kokku lugeda ja võrrelda. Kui inimene saab valesid kandeid impordiks valida, siis saab ja peabki inimene ka kontrollima. Teiseks, esimese sammu tulemusena on olemas kannete summaarne mõju -- loetelu kontodest ja muutustest -- mida ei ole raske miinuskandeks vormistada. Kui Sa SVN'i vale kataloogi 2000 failiga sisse checkid, kas Sa teed siis "svn remove" nimelise miinuskande või lähed repositooriumist neid faile ükshaaval välja noppima?
(Jan 31 '10 at 15:31)
dig
|
|
Teise variandi puhul näen ma seda probleemi, et kuna seda hetkesaldot pidevalt muudetakse, siis on sel kõrgendatud risk kuidagi viga saada. Ja kui kõik ülejäänud saldod sellest hetkesaldost sõltuvad, siis nii kui hetkesaldoga midagigi juhtub, on koheselt vigased ka kõik ülejäänud saldod. Kui aga pöörata asi vastupidiseks ja lähtuda mitte lõpp- vaid algsaldost, siis taolist probleemi pole, kuna algsaldot pea kunagi ei muudeta (või on see hoopistükkis alati nullis). Muidugi pole algusest saadik arvutamine kuigi effektiivne, seega pöörduksin ma su esimese idee suunas. Kuid vaheseisude salvestamine peaks toimuma mitte nädala, kuu või aasta kaupa, vaid teatude tehingute arvu kaupa - näiteks peale igat sajandat tehingut - nõndaviisi ei sõltu asjad sellest, kas kuus juhtutakse tegema 5 või 5000 tehingut. Ning lõpuks võib olla effektiivsuse mõttes kasulik hoida meeles ka toda hetkesaldot, kuid nüüd ei sõltuks sellest enam kõik mustmiljon kunagi tehtud tehingut vaid maksimaalselt viimased sada. Vigane saldo on eeldatavasti erijuht ja haruldus, mitte common case. Kui hetkesaldo katki läheb, siis on seda lihtne taastada - summeerida kõik tehingud aegade algusest. Aga tehingute arvu järel saldo salvestamine on tõesti parem mõte kui kuu lõpus, kuna jaotab saldod ühtlasemalt.
(Jan 27 '10 at 10:56)
Tambet Matiisen ♦♦
Korralik ACID-compliant SQL-süsteem ei kirjuta üldiselt kirjeid füüsiliselt üle, vaid teeb uue kirje ja uuendab viita. See tähendab sageli, et kirje üksinda katki minemise tõenäosus ei sõltu sellest, kui sageli seda kirjet UPDATE'itakse. Kui kirje lendab, siis ikka koos kettaga :-) Ja selle vastu aitab backup.
(Jan 30 '10 at 09:01)
dig
Ma ise mõtlesin ka nii, et vaevalt nüüd tihe andmebaasipäringute arv selle välja pihta suurt halba suudab teha, kuid miski siiski jäi närima mind seespoolt kui ma mõtlesin selle peale, et kõik muu sõltub millestki väga sageli muutuvast. Kuid kui Tambet kinnitas, et hetkesaldo on väga lihtsasti taastatav, siis nüüd ma selle koha pealt enam ei muretse.
(Jan 30 '10 at 20:48)
Rene Saarsoo ♦♦
|
|
Kui üldistada iga N kande kaupa summeerimist, siis võiks hoopis hoida kannete summasid kahendpuuna -
Sellisel juhul on suvalisele kandele vastava saldo leidmiseks vaja log(n) osasummat kokku liita, sama kallis ka kande väärtuse muutmine ja uue kande lõppu lisamine Teoreetiliselt väga ilus lahendus, muidugi. Aga kui vaadata praktilist olukorda, nagu kirjeldatud Tambeti kommentaaris Antoni vastusele, siis võib kergesti juhtuda, et lisaks kirjetes olevatele väärtustele muutub ka kirjete arv ja selle olukorra parandamine on juba palju kallim lõbu. Vahest oleks kahendpuu asemel parem kaaluda vahesummade hoidmist mingis skip list moodi struktuuris (http://en.wikipedia.org/wiki/Skip_list).
(Jan 28 '10 at 07:57)
Ahto Truu ♦♦
|
|
Mulle meeldib originaalne lahendus kus iga tehingu juures on ka saldo. Ma oletan, et probleem tekib situatsioonis kus keegi muudab andmeid 200 kannet tagasi ja nüüd on vaja kõik need kanded ümber arvutada. Edasi ma oletan et hetkel on see realiseeritud tsükliga üle vastavate kannete ning iga ümberarvutatud kirje kohta tehakse kirjele UPDATE. Ja kui mitu kasutajat teeb sarnast operatsiooni sama tabeli kallal, siis tekib meil "pudelikael". Pakun välja, et seda operatsiooni saab andmebaasi tasemel optimiseerida ja pudelikaela vältida. Lahenduse sisuks oleks kasutada nn BULK UPDATE ehk siis teha ainult üks UPDATE nende 200 kirje uuendamiseks mis tuli ümber arvutada. Realiseerida saaks seda mitut moodi. Üheks lahenduseks oleks kopeerida need 200 rida kõigepealt TEMPORARY tabelisse ja teha seal ümberarvutused ning siis uuendada tulemused tagasi põhitabelisse ühe UPDATE abi:
Kuna Postgresql toetab massiive (arrays), siis veelgi efektiivsem on kasutada funktsiooni, mis teostab ümberarvutused massiivides ja tagastab siis tulemuse multidimensionaalse massiivina, mida siis UPDATE lauses saaks kasutada TBL_TMP asemel. Oracle andmebaasis oleks seda näiteks suht lihtne teha, kuid küllap on miskitmoodi tehtav ka Postgres. Tulemus peaks olema see, et andmebaasi jõudlus ei pudelikaela ei teki isegi kui mõnel kasutajal peaks olema vaja teostada mitme tuhande kande ümberarvutus. Täiendavalt võib muidugi kaaluda, et ehk annab kogu 200 kande kontojäägid ühe SQL-iga ära uuendada:
Seda viimast varianti praegu kasutangi. Aga ega nendel lahendustel väga palju vahet pole, sest mõlemal juhul tuleb muuta sama palju kirjeid. Väike kiirusevahe võib-olla on, aga pigem millisekundites või sekundites. Vahepeal selgus, et osaliselt oli probleemiks "index bloat", st tihti muudetava tabeli indeks kasvas väga suureks. REINDEX leevendas probleemi mõnevõrra. http://www.postgresql.org/docs/8.1/static/routine-reindex.html
(Jan 31 '10 at 14:52)
Tambet Matiisen ♦♦
|
|
sisuliselt ei ole see ju nagu tavaline konto ja saldo vaid ikkagi mingi aretis. Tavalisel konteerimisel on ka kõik muudatused uued read (vastavalt + või - ridadena) ja ajalugu otseselt ei mõjuta ja sellisel juhul oleks mõistlik hoida iga rea juures tõesti eelmise tehingu saldot (hetkesaldo võrduks eelmine saldo + hetke konteering) ning siis oleks suvalises ajalises päringus teada (iga rea kohta) eelnev ja lõppsaldo Inimesed on ekslikud, mis teha. Oleks iga tehing käsitsi sisestatud, siis veel, aga tehinguid imporditakse teisest süsteemist. Ja mõnikord läheb asi nihu ning tuleb uuesti importida. Ja kui tehinguid on ~200, siis jääb suurel hulgal mitteaktiivseid kirjeid ripakile, mis raskendavad süsteemist arusaamist.
(Jan 27 '10 at 21:50)
Tambet Matiisen ♦♦
siis ei ole sul probleem andete lugemisel vaid ikkagi impordi aegsel sisestamisel ja peaksid tegelema ka orbude handlimisega. kui seda teha ei viitsi siis tee algsaldo saamiseks lihtne select kas subquery või eraldi päringuna
(Jan 28 '10 at 09:52)
anton
Viisakas raamatupidamises tehakse eksituste parandamiseks uued paranduskandeid, mitte ei minda vanade kannete kallale. Kompromissina on mõeldav mingisugune lühike armuaeg tüüpi "viimase 30 päeva kandeid loetakse mittekivisseraiutuiks". Päevade arv 30 päevas sõltub muidugi ärivaldkonna tavadest ja arvete maksetähtaegadest ja muust põnevast.
(Jan 28 '10 at 19:23)
dig
|
