logi sisse meist KKK

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:

  • Esimene idee oleks fikseerida saldod mingi kuu või aasta intervalliga ning igasse tehingusse neid mitte panna. Seega tuleks algsaldode leidmiseks leida esimene saldode kanne enne perioodi alguskuupäeva ning ümberarvutamisel oleks muutmist vajavaid saldode kirjeid ka vähem.

  • Teine idee oleks hoida konto hetkesaldot konto kirjes. Ehk siis perioodi lõppsaldo leidmiseks tuleb lahutada konto lõppsaldost maha kõikide tehingute summad, mis on toimunud pärast perioodi lõppu. Perioodi algsaldo saab leida juba lõppsaldost tehingute summa lahutamise teel.

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?

küsitud Jan 27 '10 at 09:32

Tambet%20Matiisen's gravatar image

Tambet Matiisen ♦♦
77791125


.. selgus et üsna tihti muudetakse vanu tehinguid ..

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:

  1. Täiendav kanne (+/-)
  2. Tühistuskanne & uus kanne

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).

link

vastatud Jan 28 '10 at 23:38

clon's gravatar image

clon
411

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.

link

vastatud Jan 27 '10 at 10:33

Rene%20Saarsoo's gravatar image

Rene Saarsoo ♦♦
1.1k101121

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 -

  • iga kande juurde salvestame selle kande enda summa
  • iga teise kande juurde summeerime eelmise kande
  • iga neljanda juurde summeerime jooksva ja eelmise paari (mis on juba kokku liidetud)
  • iga kaheksanda juurde kahe viimase neliku summa (mille saame juba olemasolevast nelikust ja paarist)

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

link

vastatud Jan 27 '10 at 22:17

sigamozart's gravatar image

sigamozart
2994

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:

update tbl_kontod tk
inner join tbl_tmp tt on (tk.id = tt.id)
set tk.konto = tt.konto, tk.j22k = tt.j22k;

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:

update tbl_kontod set j22k = j22k + p_muudatus
where konto_nimi = p_konto_nimi and kande_aeg >= p_muudatuse_aeg;
link

vastatud Jan 30 '10 at 12:07

Urmo%20Kaber's gravatar image

Urmo Kaber ♦♦
2234812

edited Jan 30 '10 at 12:29

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

link

vastatud Jan 27 '10 at 11:22

anton's gravatar image

anton
11

edited Jan 27 '10 at 11:27

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
Sinu vastus
lülita eelvaade

Jälgi seda küsimust

By Email:

Pärast sisselogimist saad tellida muudatuse teavitusi siit

By RSS:

Answers

Answers and Comments

Markdown Basics

  • *kaldkiri* või __kaldkiri__
  • **paks kiri** või __paks kiri__
  • link:[tekst](http://url.com/ "pealkiri")
  • pilt?![alt tekst](/path/img.jpg "pealkiri")
  • nummerdatud nimekiri: 1. Foo 2. Bar
  • to add a line break simply add two spaces to where you would like the new line to be.
  • põhilised HTML märgendid on samuti toetatud

Pinu tööpakkumised

kõik pakkumised »

Küsimuse sildid:

×10

küsitud: Jan 27 '10 at 09:32

nähtud: 3,779 korda

viimati uuendatud: Jan 30 '10 at 12:29

Litsents: Creative Commons Attribution License | Kontakt: info@pinu.ee