Firebird MAX() nem használ index-et

Firebird MAX() nem használ index-et
2014-02-02T22:44:41+01:00
2014-02-10T12:26:08+01:00
2022-10-15T21:55:16+02:00
mandula
Sziasztok !

Tegnap kiakadtam. Nem értettem, miért fut le brutál lassan egy egyszerű MAX() lekérdezés.

select max(t.felutve) from "Tetelek" t
pedig létre volt a mezőhöz hozva index.
Megpróbáltam ezt is:

select max(t.t_felutve) from "Tetelek" t plan (t index (indx_felutve) )
de ez meg hibát dobott:
index  cannot be used in the specified plan.
index INDX_FELUTVE cannot be used in the specified plan.



Hosszas böngészés után azt olvastam, hogy CSAK a megfelelő sorrendű index használható. (ASC/DESC)
Így próbaképpen kicseréltem a MAX() függvényt MIN() -re, és láss csodát: Azzal működik !

Mivel a dupla oda-vissza indexelés szerintem baromira leterhelné a rendszert új adatok felvitelekor, ezért nem biztos, hogy ez a jó megoldás. Vagy mégis?

Kérdés:
- Milyen megoldás létezik még?

Futtassak egy trigger minden egyes tábla minden insert/update/deletére-jére,

 ami egy "Valtoztak" táblába írja az utolsó módosítás dátumát?

A Cél, hogy mikor lekérdezik a kliensek (a beépített delphi webszerveren keresztül), hogy volt-e változás (x időpont után), akkor visszaadjon egy listát a szinkronizálandó táblák (kb 40db) neveivel és az utolsó TimeStamp-pel.
Mutasd a teljes hozzászólást!
Szia!

Szerintem indexelj nyugodtan asc-re és desc-re is!

Mivel a dupla oda-vissza indexelés szerintem ... leterhelné a rendszert új adatok felvitelekor, ezért nem biztos, hogy ez a jó megoldás. Vagy mégis?


Nem terheli annyira az annyira a rendszert, mint gondolod!


Ez érdekes...

Az eredeti hozzászólásban az idézett rész kipontozott szavára nekem visszaugat a rendszer, hogy "kérlek fogalmazz kúlturáltan..."
Akkor hogy került be az eredeti szövegbe?
mandula! Ez utóbbi megjegyzés nem ellened szól, csak "érdekes" a prog.hu!
Mutasd a teljes hozzászólást!

  • ... Attól félek, hogy ha ezt a triggeres megoldást választanám, akkor oda 3 napi melóm és kezdhetem elölről, de ez a legkevesebb... mert: Akkor ezzel

    - egyetlen tábla

    - 40db fix sorában szereplő

    - 40 timestamp íródna felül újra és újra !!!
    Ergo pillanatok alatt kinyírná a merevlemezt.
    Mutasd a teljes hozzászólást!
  • Ha ez számít, akkor : 2.1.5 adatbázis motort használok.

    Még nem tudok áttérni 2.5-re, mert csak a 2.5.3-ban javítottak pár dolgot, ami nekem kell, de az még csak béta.
    Bár újra elolvastam a 2.5-re vonatkozó Relase Notes -okat, de nem találtam volna olyat, hogy fejlesztették volna ezt a képességet! (Mármint hogy egy index-et "visszafele" is tudjon használni...)
    Mutasd a teljes hozzászólást!
  • Megtaláltam a magyarázatot, miért nem tudja a Firebird az Ascending Index -et MAX()-ra használni. Mivel az Interbase alapjaira épül, és onnan egyfajta "prefix-tömörítéses, szekvenciális indexelést örökölt." Ez úgy működik, hogy :
    1. eltárolja az index legelső elemét,
    2. aztán a második elemnél már csak csak azt a pontot jegyzi,
    amelyik karaktertől különbözik az elsőtől, és így tovább.

    Tehát ha referenciákat akar tárolni a következő 2 értékhez egy Index-ben:
    AAAAAA AAAABB
    akkor ténylegesen valami ilyesmit tárol az indexben:
    AAAAAA 4 BB
    Ez a fajta előtag-tömörítés sok helyet spórol többféle műveletnél, és elég gyorsan működik futásidőben. Ám lehetetlenné teszi, hogy visszafelé olvassa az Index-et.

    Ha az utolsó elemet kerestetnénk vele, akkor is végig kellene néznie az elejéig, hogy az mi volt.
    Mutasd a teljes hozzászólást!
  • Szia!

    Szerintem indexelj nyugodtan asc-re és desc-re is!

    Mivel a dupla oda-vissza indexelés szerintem ... leterhelné a rendszert új adatok felvitelekor, ezért nem biztos, hogy ez a jó megoldás. Vagy mégis?


    Nem terheli annyira az annyira a rendszert, mint gondolod!


    Ez érdekes...

    Az eredeti hozzászólásban az idézett rész kipontozott szavára nekem visszaugat a rendszer, hogy "kérlek fogalmazz kúlturáltan..."
    Akkor hogy került be az eredeti szövegbe?
    mandula! Ez utóbbi megjegyzés nem ellened szól, csak "érdekes" a prog.hu!
    Mutasd a teljes hozzászólást!
  • Szóval összességében 2 lehetőség közül választhatok:

    1. minden insert/update/delete után lefut egy trigger, ami egy tábla 1 sorába beírja magát, mint "last-update" azaz legnagyobb módosított.
     ... ez talán kinyírná a winyót, mert bár közben kiderítettem, hogy egy-egy új tranzakció mindig az adott tábla adott PAGE-ében egy-egy új területet kezd írni, és csak COMMIT esetén jelöli az előző területet töröltnek, Ám a törölt területeket szintén felülírja, tehát valószínűleg minden második alkalommal mégiscsak ugyanoda lenne írási művelet.

    2. mégiscsak létrehozok egy másod-indexet a "Tételek" táblához külön.

    (Már így is 5 index van a táblán, tehát lenne egy 6. a millió tételre ami tovább lassítja az újak beszúrását.)

    További problémám, hogy mi történik olyankor, ha 2 külön adatbázis szinkronizál, és régi adatok kerülnek beszúrásra (régi dátumokkal). // külön ID-tartományra szabdalva //
    Akkor ez a fajta MAX() lekérdezés nem ad info-t arról, hogy ténylegesen VOLT változás az adattáblában :(
    Mutasd a teljes hozzászólást!
  • Én is erre jutottam...

    A szinkronizációt meg lehet, hogy úgy oldom meg, hogy egyszerre figyeli a kliens az utolsó szinkronizáció dátumát, és ha az is változott, akkor az ELŐZŐ időponttól ÚJRA lekér minden adatot mégegyszer.

    ... hacsak nincs valakinek valami jobb 5lete?
    Mutasd a teljes hozzászólást!
  • Ez Dúúúrva !

    Tételek száma az adatbázisban: 883.000.-
    másod-index létrehozása előtt DB mérete : 175MB

    index létrehozása után: 235MB

    létrehozás ideje:
    * Core i5 gépen = 1 perc
    (már az is sok, mert úgy tűnik, mintha lefagyott volna a program, amíg 100%-on dolgozik az fbserver.exe a háttérben...)

    * Centrino 2GHz gépen = 15 perc !!! (ettől csak gagyibb gépek vannak szerte az országban)

    Mondjuk utána már gyors lett a lekérdezés: MAX(t.szinkron_ido)
    De Az ügyfeleim ki fognak akadni :( amikor egyik reggel bekapcsolják a gépet, és fél óráig nem tudnak dolgozni!
    ... lehet, hogy mégis inkább a triggeres megoldást kellett volna választanom?

    Ráadásul indexelés után TÖNKREMENT a próba adatbázis! Valahol a 70.000.-dik tételnél.
    Full Validation azt írta hogy :

    Record corruption: 1
    Index corruption : 2

    (Sima Validation nem talált hibát, ergo tanulságos, hogy annak nem szabad hinni!)
    Megpróbáltam csinálni egy mentést a "MEND"-elt adatbázisról kísérletképpen, de 37 perc után meguntam a 100%-os procihasználatot és lelőttem a szervert.
    Mutasd a teljes hozzászólást!
  • Ez érdekes!

    Egyik adatbázisom mérete: 815MByte.
    Egyik táblájában a rekordok száma: 2 591 754.
    Csináltam egy indexet ID-re/desc.
    Létrehozás kb 4 másodperc volt!!!
    Index létrehozása után az adatbázis mérete: 818MByte.

    Majd a select max helyett:
    select first 1 ID from adatok order by ID desc!
    Nem is tudta megmérni: 0msec alatt pitty-putty vágta vissza az eredményt!

    Pedig nem egy bika gépem van... HP laptop, rajta win7/32bit
    Tavaly vettem "ócsón"...

    FireBird 2.5.2.26540
    Mutasd a teljes hozzászólást!
  • Hmmm. Ez tényleg érdekes!
    mondjuk egy már eleve integer mezőn, ami ráadásul Unique is, gondolom könnyebben megy, mint egy NEM egyedi timestamp mezőn...
    Nincs véletetlenül egy timestamp abban az adatbázisodban? Most kíváncsivá tettél !
    Mutasd a teljes hozzászólást!
  • Bocsánat, annyiban helyesbítenem kell, hogy :
     NEM az tartott sokáig, amíg elkészítette magát az indexet, hanem hogy beszúrtam egy új mezőt:
     SZINKRON_IDO : TimeStamp;
    és feltöltöttem adattal !
    UPDATE"Tetelek" SET szinkron_ido=felutve;
    Mutasd a teljes hozzászólást!
  • TimeStamp-om az nincs...

    DE!

    Itt ez a tábla, a már említett 2 és félmilliós rekordszámmal...
    Kereken 20 db index van rajta, néhány "többmezős".

    Én az insertet tárolt eljárással csinálom!!!
    Első insert 515msec, második insert 156msec!!!!!!!!!

    Lövésem nincs, Nálad mi a gond...
    Mutasd a teljes hozzászólást!
    Csatolt állomány
  • Még egy dolog!

    !!!!Nálam nincsenek külső kulcsok!!!!
    Mutasd a teljes hozzászólást!
  • Szia!

    Lenne egy javaslatom!

    Szerintem használj GIUD-ot a TimeStamp mellett, az (elméletileg) "globálisan" egyedi.
    Így nem kell index a TimeStampra, "csak" a GUID-ra...
    Arra pedig már könnyű keresni!
    ...és szerintem könnyű szinkronizálni is!
    Mutasd a teljes hozzászólást!

  • Igen, köszönöm, én is pont erre jutottam tegnap reggel fogmosás közben :D

    Megjegyzés: kardosi előbbi hozzászólása már arra a probléma-továbbgörgetésre vonatkozott, hogy: mi alapján lehetne több adatbázist összeszinkronizálni index-ek segítségével?

    Mivel BIGINT mezőt hoztam létre erre Firebirdben, Delphi-ből így fogom feltölteni:

    uj_64bit_id := trunc(NOW() * 24.0 * 60.0 * 60.0 * 1000.0);

    Ugyanis a GUID / UUID mezők 128bit hosszúak, amit a Firebird 16 CHAR OCTET formában javasol tárolni. Annak pedig nem annyira triviális az oda/vissza konvertálása, plusz az indexelést is lassítja.

    Annak esélye, hogy 2 gépről egyszerre ugyanabban a milliszekundumban próbáljon meg 2 felhasználó feltölteni 1-1 képet > rendkívül kicsi, de ha mégis, akkor az INSERT-nél úgyis hibát dob, és a Try-Except elkapja, ergo kezelhető / újraindítható a ciklus.
    Mutasd a teljes hozzászólást!
  • Mellesleg attól még KELL a timestamp mező is !

    Mert a GUID létrehozáskor generálódik, viszont az összeszinkronizáláskor megnézi, hogy az azonos GUID-vel rendelkezőknek azonos-e a TimeStamp-je, vagy valamelyik sornak változott-e azóta a tartalma?

    Az index pedig arra fog kelleni, hogy TIMESTAMP alapján tegyem csökkenő sorrendbe, mert bizony nem fogom megúszni azt, hogy

    1. végigmenjek rajtuk egyenként,

    2. és megnézzem, hogy a lokális adatbázisban már esetleg UGYANAZ van-e,

    3. vagy menjek még régebbire vissza, megkeresve a legrégebbi közös (már szinkronizált) sort
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd