- QuickEye
- Medlem ●
- Stockholm
Hej,
Har precis skaffat mig FM 8.5 för att testa hur det känns efter många år med Access. Dvs jag är ganska nybörjare på FM.
En fråga till er, erfarna FM användare: hur kan man förbättra sökningsprestandan?
Jag har en tabell på 3,4 milj poster som är länkad till sig själv och andra tabeller. Tabellen innehåller några beräkningar baserad på self join som går inte att ha index på (om jag fattar rätt). Det tar timmar att leta fram t ex unika värden i tabellen. Kör på en MAc Pro med 6 GB minne så jag hoppas att det är inte datorn som är flaskhalsen.
Tack på förhand,
QuickEye
Det finns massa saker man kan göra!
Som du vet så förbättrar indexering sökhastigheten oerhört mycket, så det betyder att alla fält som är/kan indexeras skall indexeras. Det gör alltså FileMaker så fort du har gjort en sökning i fältet helt automatiskt, men du kan även kryssa för detta själv.
Vad som slöar ner är som du märkt beräkningar allt som inte kan lagras tex beräkningar som använder relaterade data och sortering i portaler eller poster som sorterar relaterade fält.
Det finns flera lösningar, den enklaste är förstås är att faktiskt lagra informationen ifråga om det går. Ett sätt att göra det är att via manus (FileMaker-snurror, sök på detta begrepp här i forumet) som läser av relaterad information och sedan lagrar den i ett verkligt fält. Kör man detta manus lite då och då (tex på nätter) så påverkar det inte det dagliga arbetet.
En annan lösning är att lagra data på andra sätt och en tredje är att bygga en workaround, den senare är när man helt enkelt skapar en lösning som går förbi ett olösligt problem istället för att lösa det, därav namnet.
Här är en lösning på just ditt problem med att hitta unika värden i tre miljoner poster: Om du skapat beräkningar som utgör både vänstra sidan av relationen och som är kombination av två fält som i sin tur är relaterade kan resultatet inte lagras. Därmed måste FM beräkna denna info varje gång den skall visas och med tre miljoner poster tar det tid. Jag gissar att du redan provat och misslyckats med att söka på ! i flera fält för att på det viset hitta dubbletter och då upptäckt/insett att denna sökning inte hittar dubbletter värden för flera fält. Men det betyder inte att sökning på ! inte kan användas för att lösa ditt problem. Skapa ett nytt textfält, kalla det unikt_kombivärde, tag sedan och fyll detta fält med en kombination av flera fält (du kan använda ett manus som loopar igenom alla poster eller klicka i fältet, välj Poster > Ersätt fältinnehåll, ange en beräkning (Namn & Telefonnummer) tex. Markera att fältet skall vara indexerat i fältdefinitionerna, vänta ett tag. Tag sedan och sök på ! i det fältet, då får du alla dubbletter, dvs alla icke unika värden. Välj Poster > Visa uteslutna så visas alla poster som INTE är dubbletter, dvs dina unika värden.
Lycka till!
Tack!
Antog att det fanns massor av saker att göra: just detta som gör det att man försöker att hitta det sättet som ger bästa resultat!
Jag försöker att hitta ett sätt som är båda smidig och elegant: jag vill inte skriva in massa onödig data i tabellerna men vill inte heller sitta och vänta i timmar...
Hur funkar att söka på "!"?
Visar det värden som förekommer flera gånger? I så fall de värden som är unika visas inte om man söker på !. Eller visar den en lista på unika värden där alla värden är med, men även dubletter visas en gång (som SELECT DISTINCT i SQL)?
Jag sökte på ! och får för mig att bara dubletter som visas...
Om du söker på ! så hittas dubletter, det är alldeles riktigt.
När du har gjort en sökning på dubbletter så står det kanske Hittade: 17027 och Totalt: 433326. Om du då väljer i menyn "Poster" alternativet "Visa endast uteslutna" visas istället alla de poster som inte hittades av din sökning på dubletter, det betyder ju att det är unika poster. Är du med?
Sökning på ! hittar alla poster som har samma värde i ett visst fält som någon annan post, det betyder att även tre, fyra, fem eller 857 poster som har samma värde i fältet kommer att visas. De poster som visas är alltså dubletten och "originalet" om du förstår vad jag menar. FileMaker gömmer alltså inte undan en post av ett "set" med dubbletter och visar dubbletterna för sig. Exempel, säg att värdet 857 förekommer i fältet "Kundnummer" tre gånger och värdet 9282 förekommer 12 ggr och värdet 72727 förekommer två gånger. En sökning på ! ger alltså 17 hittade poster.
Om du söker på dubbletter och sedan sorterar på det fältet du sökte i, så ser du exakt vad som hittats.
Först och främst: jag tycker jag att det är jättesnält av dig att du delar med dig din erfarenhet - jag är tacksam för din hjälp och för dina andra inlägg med bra tips!
Testade sökning på !. Vad jag menar är att unika värden är inte med på denna lista - och det är just det som jag behöver. Det är ok att vissa värden förekommer flera gånger - det måste vara så i denna tabell.
Finns det ett smidigt sätt att göra så förutom att skapa ett unikt serienummer på varje post, selfjoina fältet med värden och ge 1 där värden och serienummret är lika med motsvarande fält i selfjoin? (Antar att använda Count på värden är likvärdig lösning.)
Hur funkar det egentligen i FM? Min hjärna ("finslipad" på Access) börjar ge ut felmeddelanden...
Exempel:
fält1 serienr
aaa 1
aaa 2
aaa 3
bbb 4
bbb 5
ccc 6
Selfjoin på fält1 = fält1... Jag skulle förvänta mig att en sån join skulle knyta alla förekomster av aaa i den vänstra tabellen till alla förekomster av aaa i den högra tabellen. Så varje vänstra-aaa får tre högra-aaa, dvs 9 aaa sammanlagt. Det är hur min SQL-hjärna ser det.
Sen har jag en beräkning i tabellen: If(serienr = SelfJoin::serienr, 1, 0). Denna beräkning ger värde 1 till en enda förekomst av aaa, bbb och ccc. Dvs det funkar i praktiken. Men utav de 9 förekomster av aaa (i min hjärna) 3 har serienr = Selfjoin::serienr! Röd saftblandare snurrar runt i skallen på mig...
Lite fråger:
- jag har fel nånstans: var?
- varför får jag inte alla 9 förekomster av aaa?
- är portar det enda sättet att få fram alla förekomster? går det att göra i tabel view?
Tack!
Jag vill bara kort kolla att du fattar en sak som jag beskrivit ett par gånger nu men som jag inte ser av dina svar att du refererar till eller verkar förstå?
Om du söker på dubbletter genom att ange ! i ett fält, så hittar du dubbletter, det är du med på?
Om du omedelbart efter att du har gjort en sådan sökning väljer "Poster > Visa endast uteslutna" så får du fram alla poster som INTE är dubbletter, dvs alla unika värden, är du med på det med?
Bekräfta gärna detta innan jag ger mig på att berätta lite mera.
Ett exempel kanske förtydligar det hela, säg att en tabell innehåller
A
A
B
C
Söker du på ! i fältet så hittas två poster, som båda innehåller A, undangömda är då är två poster, B och C. Väljer du "Poster > Visa endast uteslutna", så göms de två posterna med A och istället visas två poster med B respektive C, dvs de unika värdena i denna tabell i det fältet.
Jag är med på !. Testade och kom fram till samma som du skrev. Jag kollade vilka värden förekommer bara 1 gång och de var inte med när jag sökte på !.
Sökning på ! är bra att kunna, men ger mig inte vad jag var ute i just detta sammanhang. Jag ville kolla om det är likadant som SELECT DISTINCT i Access SQL, men det är inte.
Jag behöver en lista på alla värden som förekommer, men listan behöver att innehålla varje värde 1 enda gång, även om det förekommer flera gånger i tabellen. (Det är vad SELECT DISTINCT gör.)
Nu har jag en lösning som funkar i praktiken, men går emot hur min hjärna uppfattar länkarna efter att ha jobbat mycket i Acces. Och 3x3 aaa handlar om detta, inte om "!" längre.
Allt detta blev viktigt för att alla länkar som jag har gör att databasen blev jättelångsam, trots att den är inte så himla invecklad. Nu försöker jag att "streamlinea" och kolla på olika likvärdiga sätt att få fram det jag är ute efter.:cool:
Tack!
Ok, ledsen men det verkar som om jag fortfarande misslyckas med att förklara detta för dig. Jag är helt med på att du vill göra en select distinct, precis som i SQL och jag fattar att du förstår att om du söker på ! så hittas alla värden som INTE är unika. Precis så här långt tror jag du är med.
Men vad du fortfarande inte indikerar för mig (jag missförstår dig säkert) är att du förstår genom att välja "Poster > Visa endast uteslutna" direkt efter att du har sökt på ! så får du fram alla värden som ÄR unika, dvs exakt den Select Distinct som du är på jakt efter. Dvs alla värden som inte hittades av sökningen på !. Alla poster som visas då är nämligen de som har unika värden.
Vill du ha dessa värden i en lista i ett fält eller annorstädes så finns det enkla metoder för det, men det är steg två.
Det är lungt, jag skriver lite flummigt själv...
Visa endast uteslutna på sökning på ! ger bara B och C i ditt exempel, och inte tre poster:A, B och C. Och det är vad jag är ute efter, och det är vad SELECT DISTINCT ger.
För mig är "listan på unika värden" är en lista på alla värden som förekommer i ett fält. Bara en enda av förekomster på en dubblett visas. Jag verkar använda begreppet "unikt värde" på lite annatt sätt...
Ok, du har helt rätt, A är ju inte med när man flippat sökresultatet från dubbletter till icke dubbletter. Återkommer lite senare med mera FileMaker-finesser och metoder att få fram verkligt unika värden och kanske något annat tips som handlar om hur du kan få en toksnabb databas även om den innehåller miljoner poster.
Kanon, tack så mycket! Jag testar olika metoder själv under tiden, men det säkert finns mängder av finesser som jag har ingen aning om - än!
Just nu är det lite rappare på att räkna fram Sum() från en selfjoin, men det fortfarande är långsamt att köra find på ett värde inom detta Sum fält.
Hur vill du använda de unika värdena? Ska de exporteras till något slags lista för användning i något annat program etc? Eller vill du att en uppsättning poster ska visas, och i så fall undrar jag vilken instans av dublettposterna som ska visas? (dvs. om värdet X förekommer i tre poster, vilken av dessa tre poster ska visas?)
Unika värden behöver jag för att räkna fram ett nytt värde som förekommer inte. Uppgiften är ungefär så här:
Två kunder använder samma priskod. Vi måste höja priset på ena kunden, men inte på den andre. Iom att de använder samma priskod kan jag inte höja priset bara så där då båda kunder får höjningen. Så jag måste flytta ena kunden till en helt ny priskod. För att få fram en ny kod så måste jag kolla vilka som används redan. Här används listan på förekommande värden (detta begrepp verkar vara bättre).
I detta uppgift spelar det ingen roll hur många gånger ett värde används, bara att det förekommer.
Det hade varit betydligt bättre om du hade beskrivit ditt problem på det här viset från början, då hade jag svarat betydligt kortare.
1. Om varje kund skall ha egen priskod, varför är inte priskoden och kundnummer samma sak?
2. Lösningen på detta problem verkar dock vara att faktiskt skapa unika nummer, alltså verkligt unika nummer, tex slumpmässiga textsträngar på 28 tecken i längd. Det kan du göra i ett manus eller genom att definiera en egen funktion. Det finns en textfunktion som plockar ett tecken ur en textsträng, Middle heter den. Det finns en annan som ger dig ett slumptal, kombinera dessa två så kan du skapa en funktion som skapar slumpmässiga textsträngar. Nedan ser du en funktion för detta. Definiera funktioner kan du dock göra bara om du har FileMaker Pro Advanced 8.5:
Left("Make a string containing 28 random chars from the alphabet";0) & Let ( [TheAlphabet = "ABCDEFGHIJKLMNOPQRSTUVXYZ01234567890"];
Middle ( TheAlphabet ; Random*Length(TheAlphabet) ; 1 ) &
Middle ( TheAlphabet ; Random*Length(TheAlphabet) ; 1 ) &
Middle ( TheAlphabet ; Random*Length(TheAlphabet) ; 1 )
... upprepa näst sista raden om och om igen tills du har 28 tecken...
osv...
)
3. Ett löpnummer är en annan metod, varje gång en ny priskod skapas får den ett löpnummer, detta är ju unikt vilket är den enklaste lösningen. En metod att skapa sådana löpnummer är antingen att sätta ett fält i priskodtabellen att vara löpnummer (definiera fält > fältet > automatiska data > kryssa för löpnummer), eller så låter du löpnumret skapas genom att manus. I en speciell tabell med endast en post (som jag brukar kalla Reg) så har du räknare_priskodfältet, via manus räknar du upp priskodnumret, läser av det och lagrar det i den nya posten.
Lycka till!
Glömde en vanlig metod för punkt 3 som är ganska snabb för att hitta "nästa lediga nummer". Man skapar ett manus som:
1. Visar alla poster.
2. Sorterar på numret.
3. Går till sista posten
4. Läser av numret, lägger till 1 för att skapa nästa lediga nummer.
I ditt fall med en miljon poster är den kanske inte så snabb, men den borde vara snabbare icke beräknade relationer i alla fall.
Ännu en metod är förstås att lagra priskoder i en separat tabell och generera dessa före de används och när man behöver en, ta en ur tabellen och markera den som använd. Detta går att göra med några enkla manussteg:
För att skapa koder (pseudkod för FileMaker):
Gå till tabellen/layouten, Bearbeta
Ladda en räknare med ett värde, tex 10.000 (dvs ett variabefält, numeriskt, i FM 8.5 finns även manussteget skapa variabel som kan användas i manus.)
Starta en loop, skapa en post, tilldela posten en kod (här skall det vara någon knasig beräkning som skapar koder baserad på någon komplicerad räkneövning med checksiffror och allt, tänk tex serienummer för programvaror, OCR-nummer och liknande).
Räkna ner ett från räknaren
Om räknaren är noll, lämna loopen (Exit loop if-steget)
Avsluta loopen.
För att läsa av en priskod:
Skapa ett beräkningsfält i priskoder som är baserat på villkoret att om denna posts nummer är använt, så är värdet tomt, i annat fall, så innehåller det X.
Skapa en relation mellan tabellen där priskoden skall läsas av på ett beräkningsfält som alltid innehåller "X" och priskoder på beräkningsfältet ovan.
I ett manus läs av priskoden via relationen och märk den som använd när det är gjort via denna relation. Dvs via tilldela fält.
Det fungerar så i FileMaker att om en relation ger flera hittade poster "där borta" så kan FileMaker mycket väl och enkelt jobba med den första posten via relationen, när den är markerad som använd slår villkoret i beräkningen till ovan och då är den posten inte först längre och försvinner så att säga, och ersätts med nästa oanvända. Fiffigt eller hur?
Tack för alla tips!
Du har rätt, det kanske är bättre att beskriva uppgiften lite mera - my miss...
Jag har redan gjort detta i Acces några gånger, så det som är nyast för mig är att använda FM. Meningen med att kolla hur "förekommande värden" kan visas i FM var att få hjälp med ett steg i analysarbetet, inte nödvändigtvist hela uppgiften.
Hursom...
Uppgiften är att höja priserna på tusentals kunder.
Det urgamla faktureringssystemet tillåter förändringar uteslutande genom användargränsnittet, och är inte anpassad för att hantera sådana massvisa uppdateringar. Därför tankar vi ner tabellerna från detta system som jag laddar upp i FM där jag analyserar data och hanterar alla förändringar med hjälp av en manus. Jag skapar nya tabeller som vi sedan tankar upp i faktureringssystemet, och voilá - vi har nya priser!
Tyvärr är det ingen utveckling av faktureringssytemet, "bara" att ta skiten från ett system, jonglera med data på ett smart sätt i ett annat system där man kan jonglera med data, sen tanka upp det nya data i faktureringssystemet. Dvs jag styr inte hur koderna väljs, jag anpassar mig hur faktureringssystemet gör.
I faktureringssystemet väljer användare själva vilka koder de vill skapa, dvs det är inte systemet som automatiskt ger en ny kod. Detta innebär att folk väljer koder som har någon betydelse för de, och på så sättet följer koder inte varan i sträng ordning: de är huller om buller.:tveksam:
Kunder delar priser med varann, dvs två eller hur många som helst kunder ha samma priskod. Om två grupper av kunder ("höja" och "ej höja" - vi får listan av säljarna) använder samma priskod då måste vi flytta ena gruppen till en ny kod, annars antigen båda grupper eller varken av de får höjningen.
För att lösa sådana "krockar" måste man kolla vilka priskoder som krockar. Sedan skapar man nya priskoder för att ersätta priskoderna i en av grupperna. Här använder jag listan på förekommande värden.
Priskoderna är 3 karaktär långa där 0-9 och det latinska alfebetet är tillåtna. 36 karaktärer sammanlagt. Jag behandlar denna kod till som nummer i bas 36 och konverterar till ett nummer i bas 10: med nummer kan man man kan lätt sortera och räkna fram skillnaden mellan olika koder. Här använder jag Middle() och tack för tippsen om Let() - jag skrev ut hela listan på alla 36 karaktärer.:">
Iom nästa lediga nummret är inte nödvändigt är det sista +1, så letar manuset igenom listan på förekommande värden och väljer en "lucka" där skillnaden mellan koder som följer varann enligt sorteringen är högre än 1. Den nya koden i bas 10 räknas om till ett nummer i bas 36 och las till till listan på förekommande värden. Fram till nästa priskod som krockar och börja om...
Det blir en likadan manus till för att även olika priskoder använder samma prisberäkningar, och där kan krockar förekomma också. Som tur är så det är likadana koder.
I Acces körde jag med SELECT DISTINCT. I FM ger jag varje rad inom tabellen som innehåller kundnr och priskod (det finns ingen tabell bara på priskoderna iom faktureringssytemet är inte relational databas) ett löpnummer. Self join och If() ger mig en flag ("Unique") som identifierara en enda förekomst av varje priskod. Find på denna flag visar en lista på alla förekommande värden, utan upprepningar.
Det som jag frågade om var hur FM funkar gentemot Acces när det gäller länkar. Som jag skrev, jag skulle förvänta mig att 9 värden i mitt exempel (se exemplet med 3 stycker aaa i min tidigare inlägg). Och 3 av de 9 har den där flag, dvs bör visas om jag kör find på "Unique". Men jag får ett enda värde som får flag, som är precis vad jag är ute efter, men då är jag förvirrad om hur join väljer vilka värden som matchas. Hur funkar detta i FM egentligen?
Tack!
Okej, jag är ingen FM-expert, men jag kan en eller två saker om AppleScript och ShellScripting, och där är en sån här sak lätt att lösa, så följande script hämtar alla unika värden, läser av det högsta, ökar med 1 för att få nästa lediga unika värde, och stoppar in värdet i angivet fält på aktuell post.
"set cellValue of cell \"Målfält\" of current record to (paragraph -1 of (do shell script \"echo '" & List(kasta 2::Källfält) & "' | tr '\\\r' '\\\n' | sort -n | uniq " & "\") as integer +1)"
Det man behöver ändra för att köra det i sin egen databas är att man behöver en självrelation som alltid ger alla poster (x) och byta ut den del av min kod som heter "kasta 2::Källfält"
Likaså behöver man ändra namnet "Målfält" till namnet på det fältet i den egna databasen där man vill stoppa in resultatet
Hur det står sig prestandamässigt vet jag inte. Själva AppleScript/Shell-delen är löjligt snabb men hur snabbt FM hämtar data via List-funktionen beror ju på om dessa redan är indexerade etc
Fördelen med scripting (i det här fallet) är att man kan komma åt kommandot "uniq" som ger precis det du vill. För att Uniq ska funka som det ska måste det först köras genom "sort" som sorterar listan". Sort i sin tur kräver att alla radbrytningar är unix-radbrytningar, vilket är vad kommandot "tr" i mitt fall gör.
Att man behöver använda AppleScript är bara för att FM kan utfärda AppleScript-kommandon, men inte direkt shell-kommandon. Alltså använder mitt exempel AppleScript bara som en brygga.
Att det ser så krångligt ut är bara för att såväl FM som AS och Shell kräver att man "escapar" alla specialtecken, därav alla backslashes etc
Syntaxen kanske ser lite krånglig ut men logiken är enkel
* Hämta alla värden (FM)
* Byt ut alla radbrytningar (Shell)
* Sortera listan (Shell)
* ta fram unika värden (Shell)
* Ta sista (högsta) värdet och öka med ett (AS)
* Stoppa in värdet i en cell (AS)
Jag var bortrest i ett tag...
Jag måste kolla hur shellscripting och AS funkar. Iofs, FMs egen scripting funkar bra än så länge, men jag är alltid nyfiken på nya sätt att lösa problem!
I praktiken funkar min databas utan problem, men jag fortfarande fattar inte hur selfjoin på 3 poster ger bara 3 poster och inte 9... Finns det beskrivet nånstans? Tack!
Posten du står i (en post) "tittar via" en relation aka "ett titthål i väggen" (eller vilken metafor du nu vill använda) och "ser" ett antal poster via denna relation, alltså tre poster.
Det är inte så att tre visade poster samtidigt tittar genom samma relation samtidigt och var och en av dessa tre poster ser samma tre poster, totalt nio poster. Det finns ju inte nio poster, det finns ju tre.
Relationer utvärderas i den kontext du befinner dig och det är layouten (vilken tabellförekomst den visar poster från) och posten du står i och var den befinner sig i relationsdiagrammet.
Det finns ett manussteg som är ett frånsteg från denna regel: "Gå till relaterade poster", där man kan ange "Visa endast relaterade poster" med de två underalterantiven:
* Matcha endast relaterad post
* Matcha alla poster i aktuellt sökresultat
Den första betyder "Jag står på en post, det är bara dess relaterade poster jag vill hitta via relationen när jag hoppar dit", den andra betyder "Jag står på en post och brevid mig finns några till, ett helt gäng faktiskt, när jag hoppar via relationen så vill jag och alla mina kompisar som jag kallar för "hittade poster", se alla relaterade poster där borta, vi tar med chips, dip och vodka och så har vi en fest!" om man nu skall uttrycka sig i tekniska termer...
Tack, jag började experimentera lite och efter att ha fått det att funka i praktiken började jag ana hur det funkar. Det skiljer ser lite från vad jag är van vid, men det är bara att vänja mig.
Det verkar så att databasen funkar, alla manus gör vad de bör göra och slutresultatet (data som kommer ut efter all processing) är det jag är ute efter. Tack för all hjälp och tips!