Oprettet tir. d. 09. marts 2010 kl. 15:12:12

tigerdyr2007
tigerdyr2007 (7.880 point. Point ude: 0)

Optimering

Hej

Jeg har et optimeringsproblem, det relaterer sig til spm http://www.eksperten.dk/ (...)
Det er klart at nedenstående kode tager lang tid at afvikle (ca. 2 min for 1000 rekvirenter med 2000 kontakter). Og den tid vil jo vokse eksponentielt med udbygningen :-(
Har i nogen triks til hvordan det kan speedes op, eller gøres mere effektivt.
Opgaven er simpel, find alle dem som releterer til en post, tag deres initaler, og læg til en teksstreng i den pågældende post. Denne info skal opdateres ved nye/slettede relationer, og nemmest er jo at lave det hele igen.

Mvh.

Option Compare Database
Option Explicit

Public Function update_RR_contact_field()
On Error GoTo Errorhandler

    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Dim rst2 As DAO.Recordset
    Dim rst3 As DAO.Recordset
    Dim RR_contacts_string As String
    Dim sSQL As String
    Dim sSQL2 As String
    Dim sSQL3 As String
    Dim sSQL4 As String

    Dim temp As Integer
    temp = 0
    'DoCmd.Hourglass True
   
    'Vælg alle de rekvirenter som har en relation til RR-person
    sSQL = "SELECT tbl_rekvirent.ID, tbl_RR_person.forkortelse, tbl_rekvirent_RR_person.primarykontact, tbl_rekvirent_RR_person.julekort " & _
        "FROM tbl_rekvirent INNER JOIN (tbl_RR_person INNER JOIN tbl_rekvirent_RR_person ON tbl_RR_person.ID = tbl_rekvirent_RR_person.RR_personID) ON tbl_rekvirent.ID = tbl_rekvirent_RR_person.rekvirentID ORDER BY tbl_rekvirent.ID;"
    Set db = CurrentDb
    Set rst = db.OpenRecordset(sSQL, dbOpenSnapshot)
   
    DoCmd.SetWarnings False
   
    If Not rst.BOF Then rst.MoveFirst
    Do Until rst.EOF
        RR_contacts_string = ""
        'Find de primære relationer
        sSQL2 = "SELECT tbl_RR_person.forkortelse " & _
            "FROM tbl_rekvirent INNER JOIN (tbl_RR_person INNER JOIN tbl_rekvirent_RR_person ON tbl_RR_person.ID = tbl_rekvirent_RR_person.RR_personID) ON tbl_rekvirent.ID = tbl_rekvirent_RR_person.rekvirentID " & _
            "WHERE (((tbl_rekvirent.ID)=" & rst.Fields(0) & ") AND ((tbl_rekvirent_RR_person.primarykontact)=True));"
        Set rst2 = db.OpenRecordset(sSQL2, dbOpenSnapshot)
       
        If Not rst2.BOF Then rst2.MoveFirst
        Do Until rst2.EOF
            RR_contacts_string = RR_contacts_string & rst2.Fields(0) & " "
            'MsgBox rst2.Fields(0), vbOKOnly, RR_contacts_string & "rst2" ' testudlæsning
        rst2.MoveNext
        Loop
       
        'Find sekundære relationer
        sSQL3 = "SELECT tbl_RR_person.forkortelse " & _
            "FROM tbl_rekvirent INNER JOIN (tbl_RR_person INNER JOIN tbl_rekvirent_RR_person ON tbl_RR_person.ID = tbl_rekvirent_RR_person.RR_personID) ON tbl_rekvirent.ID = tbl_rekvirent_RR_person.rekvirentID " & _
            "WHERE (((tbl_rekvirent.ID)=" & rst.Fields(0) & ") AND ((tbl_rekvirent_RR_person.primarykontact)=False));"
        Set rst3 = db.OpenRecordset(sSQL3, dbOpenSnapshot)
       
        If Not rst3.BOF Then rst3.MoveFirst
        Do Until rst3.EOF
            RR_contacts_string = RR_contacts_string & rst3.Fields(0) & " "
            'MsgBox rst3.Fields(0) & " - " & rst.Fields(0), vbOKOnly, RR_contacts_string & "rst3" ' testudlæsning
        rst3.MoveNext
        Loop
       
        RR_contacts_string = Left(RR_contacts_string, Len(RR_contacts_string) - 1) 'Fjern sidste charecter
       
        'MsgBox RR_contacts_string, vbOKOnly, rst.Fields(0) ' testudlæsning
        'Opdater feltet rekvirenttabellen
        sSQL4 = "UPDATE tbl_rekvirent SET tbl_rekvirent.RR_contacts = '" & RR_contacts_string & "' WHERE (((tbl_rekvirent.ID)=" & rst.Fields(0) & "));"
        DoCmd.RunSQL sSQL4
       
        'Afbryder til begrænset test
        'temp = temp + 1
        'If temp = 5 Then
        '    GoTo Exit_fcn
        'End If
    rst.MoveNext 'næste rekvirent
    Loop
   
    GoTo Exit_fcn
   
Exit_fcn:
    'DoCmd.Hourglass = False
    DoCmd.SetWarnings True
    Set db = Nothing
    Set rst = Nothing
    Set rst2 = Nothing
    Set rst3 = Nothing
    Exit Function

Errorhandler:
    MsgBox Err, vbOKOnly, "Fejl"
    GoTo Exit_fcn
   
End Function

Skrevet tir. d. 09. marts 2010 kl. 15:34:19| #1

janus_007
janus_007 (30.005 point)
Du kunne evt. lave det med en stored procedure! (terry is wrong here)

Det som nok er den største performancekiller her, er Access i sig selv, men på den anden side.. hvor ofte skal du trække data ud sådan?

Den bedste løsning ville nok være at forklare trykkeriet omkring data-relationer og så levere det som Xml :)

Skrevet tir. d. 09. marts 2010 kl. 15:42:43| #2

terry
terry (244.617 point)
(terry is wrong here)
How can I be wrong here if I havent made any comments here? :o)

And in Access you cant make stored procedures!

Skrevet tir. d. 09. marts 2010 kl. 15:44:26| #3

tigerdyr2007
tigerdyr2007 (7.880 point)
I think janus_007 is refering to you coment in my previous thread... I will still be very happy to recieve any comments.

Skrevet tir. d. 09. marts 2010 kl. 17:59:00| #4

janus_007
janus_007 (30.005 point)
Jo man kan da godt lave sprocs i Access (Terry is wrong here, again) :-P

tigerdyr -> En måde du måske kunne speede det op på er ved at bruge memory lidt mere, tag denne her eks.vis:

sSQL2 = "SELECT tbl_RR_person.forkortelse " & _
            "FROM tbl_rekvirent INNER JOIN (tbl_RR_person INNER JOIN tbl_rekvirent_RR_person ON tbl_RR_person.ID = tbl_rekvirent_RR_person.RR_personID) ON tbl_rekvirent.ID = tbl_rekvirent_RR_person.rekvirentID " & _
            "WHERE (((tbl_rekvirent.ID)=" & rst.Fields(0) & ") AND ((tbl_rekvirent_RR_person.primarykontact)=True));"

For hver række i rst laver du en where-clause og eksekverer imod basen, jeg ville nok hellere læse det ind på en gang og så bruge de indbyggede .Filter på de ADO Recordsets der, altså lave et stort join, hvis du forstår :)

Skrevet tir. d. 09. marts 2010 kl. 18:15:50| #5

terry
terry (244.617 point)
stored queries in Access are the equivalent of Stored procedures in MSSQL.
http://www.stardeveloper.com/ (...)

But they are NOT the same. Stored procedures in SQL server are MUCH more powerfull than what Access is capable of. In Access it is just SQL stataments, in SQL server you can execute code.

So if you mean that an Access query is the same as a stored procedure than OK, I'm wrong :o)

Skrevet tir. d. 09. marts 2010 kl. 18:17:53| #6


Skrevet tir. d. 09. marts 2010 kl. 18:23:41| #7

janus_007
janus_007 (30.005 point)
Jamen det ved jeg da godt :-P Jeg har nu heller aldrig påstået at man kunne skrive T-sql deri, anyway.. lad os nu prøve at finde en god løsning til tigerdyret :)

Skrevet tir. d. 09. marts 2010 kl. 19:25:36| #8

tigerdyr2007
tigerdyr2007 (7.880 point)
Hehe, har jeg nu fået aktiveret en hel diskussion af Access vs MYSQL

Jeg vil lige se om jeg har forstået dig ret janus_007. Giver det lige et shot, men er ikke 100 på hvad du mener.

Skrevet tir. d. 09. marts 2010 kl. 21:06:16| #9

janus_007
janus_007 (30.005 point)
Hvad præcist er du ikke med på?

Hvis du ikke er så meget på at lave en stort join, så hent som det mindste alle records ud, sådan her:

sSQL = "SELECT tbl_rekvirent.ID, tbl_RR_person.forkortelse, tbl_rekvirent_RR_person.primarykontact, tbl_rekvirent_RR_person.julekort " & _
        "FROM tbl_rekvirent INNER JOIN (tbl_RR_person INNER JOIN tbl_rekvirent_RR_person ON tbl_RR_person.ID = tbl_rekvirent_RR_person.RR_personID) ON tbl_rekvirent.ID = tbl_rekvirent_RR_person.rekvirentID ORDER BY tbl_rekvirent.ID;"

Behold den, og så i din anden:
sSQL2 = "SELECT tbl_RR_person.forkortelse " & _
            "FROM tbl_rekvirent INNER JOIN (tbl_RR_person INNER JOIN tbl_rekvirent_RR_person ON tbl_RR_person.ID = tbl_rekvirent_RR_person.RR_personID) ON tbl_rekvirent.ID = tbl_rekvirent_RR_person.rekvirentID " & _
            "WHERE (((tbl_rekvirent.ID)=" & rst.Fields(0) & ") AND ((tbl_rekvirent_RR_person.primarykontact)=True));"
        Set rst2 = db.OpenRecordset(sSQL2, dbOpenSnapshot)

Den skriver du om til:
sSQL2 = "SELECT tbl_RR_person.forkortelse " & _
            "FROM tbl_rekvirent INNER JOIN (tbl_RR_person INNER JOIN tbl_rekvirent_RR_person ON tbl_RR_person.ID = tbl_rekvirent_RR_person.RR_personID) ON tbl_rekvirent.ID = tbl_rekvirent_RR_person.rekvirentID " & _
            "WHERE tbl_rekvirent_RR_person.primarykontact=True;"
        Set rst2 = db.OpenRecordset(sSQL2, dbOpenSnapshot)

Det henter du bare ud og så ved at bruge .Filter på Recordsettet kan du se at tingene kører langt hurtigere end når du laver en 'where' og eksekverer hver gang.

Skrevet ons. d. 10. marts 2010 kl. 10:00:00| #10

tigerdyr2007
tigerdyr2007 (7.880 point)
Hmm, jeg er nok et fjols, men jeg kan ikke finde ud af at bruge .filter, får hele tiden en fejl...
Jeg har indsat hele den opdaterede kode nedenunder igen.
Og jeg ved godt at rst2 og rst3 kan være det samme hvis jeg blot udbygger filter en smule. Vil lige have det til at funke først.

Her er hvad jeg gør
        strfilter = "tbl_rekvirent.ID = " & rst.Fields(0)
        rst2.filter = strfilter
        Set rstnew2 = rst2.OpenRecordset
       
        If Not rst2.BOF Then rst2.MoveFirst
        Do Until rst2.EOF
            RR_contacts_string = RR_contacts_string & rst2.Fields(0) & " "
            'MsgBox rst2.Fields(0), vbOKOnly, RR_contacts_string & "rst2" ' testudlæsning
        rst2.MoveNext
        Loop


Det er linien "Set rstnew2 = rst2.OpenRecordset" der giver fejl.

--------------------------------------
Hele koden:
--------------------------------------

Public Function update_RR_contact_field()
'On Error GoTo Errorhandler

    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    Dim rst2 As DAO.Recordset
    Dim rst3 As DAO.Recordset
   
    Dim rstnew2 As DAO.Recordset
    Dim rstnew3 As DAO.Recordset
   
    Dim RR_contacts_string As String
    Dim sSQL As String
    Dim sSQL2 As String
    Dim sSQL3 As String
    Dim sSQL4 As String

    Dim temp As Integer
    temp = 0
    DoCmd.Hourglass True
    Dim strfilter As String
   
    'Vælg alle de rekvirenter som har en relation til RR-person
    sSQL = "SELECT tbl_rekvirent.ID, tbl_RR_person.forkortelse, tbl_rekvirent_RR_person.primarykontact, tbl_rekvirent_RR_person.julekort " & _
        "FROM tbl_rekvirent INNER JOIN (tbl_RR_person INNER JOIN tbl_rekvirent_RR_person ON tbl_RR_person.ID = tbl_rekvirent_RR_person.RR_personID) ON tbl_rekvirent.ID = tbl_rekvirent_RR_person.rekvirentID ORDER BY tbl_rekvirent.ID;"
    Set db = CurrentDb
    Set rst = db.OpenRecordset(sSQL, dbOpenSnapshot)
   
    DoCmd.SetWarnings False

    sSQL2 = "SELECT tbl_RR_person.forkortelse " & _
        "FROM tbl_rekvirent INNER JOIN (tbl_RR_person INNER JOIN tbl_rekvirent_RR_person ON tbl_RR_person.ID = tbl_rekvirent_RR_person.RR_personID) ON tbl_rekvirent.ID = tbl_rekvirent_RR_person.rekvirentID " & _
        "WHERE tbl_rekvirent_RR_person.primarykontact=True;"
    Set rst2 = db.OpenRecordset(sSQL2, dbOpenSnapshot)
       
    sSQL3 = "SELECT tbl_RR_person.forkortelse " & _
        "FROM tbl_rekvirent INNER JOIN (tbl_RR_person INNER JOIN tbl_rekvirent_RR_person ON tbl_RR_person.ID = tbl_rekvirent_RR_person.RR_personID) ON tbl_rekvirent.ID = tbl_rekvirent_RR_person.rekvirentID " & _
        "WHERE tbl_rekvirent_RR_person.primarykontact=False;"
    Set rst3 = db.OpenRecordset(sSQL3, dbOpenSnapshot)


    If Not rst.BOF Then rst.MoveFirst
    Do Until rst.EOF
        RR_contacts_string = ""
       
        'MsgBox "hmm"
        strfilter = "tbl_rekvirent.ID = " & rst.Fields(0)
        rst2.filter = strfilter
        Set rstnew2 = rst2.OpenRecordset
       
        If Not rst2.BOF Then rst2.MoveFirst
        Do Until rst2.EOF
            RR_contacts_string = RR_contacts_string & rst2.Fields(0) & " "
            'MsgBox rst2.Fields(0), vbOKOnly, RR_contacts_string & "rst2" ' testudlæsning
        rst2.MoveNext
        Loop
       
        'Find sekundære relationer
        strfilter = "tbl_rekvirent.ID = " & rst.Fields(0)
        rst3.filter = strfilter
        Set rstnew3 = rst3.OpenRecordset
       
        If Not rst3.BOF Then rst3.MoveFirst
        Do Until rst3.EOF
            RR_contacts_string = RR_contacts_string & rst3.Fields(0) & " "
            'MsgBox rst3.Fields(0) & " - " & rst.Fields(0), vbOKOnly, RR_contacts_string & "rst3" ' testudlæsning
        rst3.MoveNext
        Loop
       
        RR_contacts_string = Left(RR_contacts_string, Len(RR_contacts_string) - 1) 'Fjern sidste character
       
        'MsgBox RR_contacts_string, vbOKOnly, rst.Fields(0) ' testudlæsning
        'Opdater feltet i rekvirenttabellen
        sSQL4 = "UPDATE tbl_rekvirent SET tbl_rekvirent.RR_contacts = '" & RR_contacts_string & "' WHERE (((tbl_rekvirent.ID)=" & rst.Fields(0) & "));"
        DoCmd.RunSQL sSQL4
       
        'Afbryder af loop til begrænset test
        temp = temp + 1
        If temp = 5 Then
            GoTo Exit_fcn
        End If
    rst.MoveNext 'næste rekvirent
    Loop
   
    GoTo Exit_fcn
   
Exit_fcn:
    DoCmd.Hourglass False
    DoCmd.SetWarnings True
    Set db = Nothing
    Set rst = Nothing
    Set rst2 = Nothing
    Set rst3 = Nothing
    Exit Function

Errorhandler:
    MsgBox Err, vbOKOnly, "Fejl"
    GoTo Exit_fcn
   
End Function

Skrevet ons. d. 10. marts 2010 kl. 12:50:02| #11

janus_007
janus_007 (30.005 point)
Når filteret er sat, så skal du ikke åbne recordsettet.
Dvs.

'MsgBox "hmm"
        strfilter = "tbl_rekvirent.ID = " & rst.Fields(0)
        rst2.Filter = strfilter
       
        If Not rst2.BOF Then rst2.MoveFirst
        Do Until rst2.EOF
            RR_contacts_string = RR_contacts_string & rst2.Fields(0) & " "
            'MsgBox rst2.Fields(0), vbOKOnly, RR_contacts_string & "rst2" ' testudlæsning
        rst2.MoveNext
        Loop


:)

Skrevet ons. d. 10. marts 2010 kl. 15:36:47| #12

tigerdyr2007
tigerdyr2007 (7.880 point)
Hmm, ja nu kører det, men har ikke rigtigt sparet noget, det tager stadig ca. samme tid, måske en anelse hurtigere, men ikke noget revolutionerende...

Skrevet ons. d. 10. marts 2010 kl. 19:55:20| #13

tigerdyr2007
tigerdyr2007 (7.880 point)
Hov, jo man skal åbne recordset! Fandt lige ud af den ikke havde filtereret, bare lagt alle data ind i hvert eneste felt.
Fra Access hjælp:

"Recordset.Filter Property: Sets or returns a value that determines the records included in a subsequently opened Recordset object (Microsoft Access workspaces (Access workspace only). Read/write String."

Skrevet tor. d. 11. marts 2010 kl. 01:19:52| #14

janus_007
janus_007 (30.005 point)
hej tigerdyr.

Nope... se her: http://www.asp101.com/ (...) , godt nok er det lang tid siden jeg arbejdede med ASP, men jeg syntes nu nok at kunne huske :)

Det undrer mig en del at det ikke går hurtigere, det lyder ekstremt anderledes nemlig.

Prøv evt. også at rette din cursortype til adOpenForwardOnly :)

Derudover kunne jeg godt tænke mig du bare tog tid på den første med og uden Filter, og egentlig også tid på open connection og OpenRecordSet, sådan at vi få nogle mere afskærmede informationer.

Skrevet tor. d. 11. marts 2010 kl. 01:20:53| #15

janus_007
janus_007 (30.005 point)
DAO -> dbOpenForwardOnly

Skrevet tor. d. 11. marts 2010 kl. 10:33:24| #16

tigerdyr2007
tigerdyr2007 (7.880 point)
Hey janus_007, det er altså ikke rigtigt. Mit citat er taget fra MS Access hjælp, og hvis jeg ikke gør som jeg har beskrevet får jeg ikke rst. filtreret først, og får alle records med.
ASP er vel heller ikke det samme som Access...

Jeg takker dog meget for indsatsen, og vil prøve med tidsmålinger, dbOpenForwardOnly etc. senere.

Skrevet tor. d. 11. marts 2010 kl. 14:20:25| #17

janus_007
janus_007 (30.005 point)
hmm næh nej det har du jo ret i :)

Skrevet søn. d. 14. marts 2010 kl. 20:24:24| #18

tigerdyr2007
tigerdyr2007 (7.880 point)
Har leget lidt med tidsmåling på openrecordset og dbOpenForwardOnly, umiddelbart giver de begge metoder samme tid.

Skrevet søn. d. 22. august 2010 kl. 14:22:44| #19

tigerdyr2007
tigerdyr2007 (7.880 point)
Ingen andre har givet et svar, jeg lukker.

Skriv et indlæg




Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] [img]link til billede[/img]
Web- og emailadresser omdannes automatisk til links

Log ind

   

   

Seneste spørgsmål

Dato og Klokkeslet "Live"

Oprettet den 11. februar 2012 kl. 19.39
jmarques giver 60 point for svar | Giv et svar »

Link til et dokument

Oprettet den 10. februar 2012 kl. 14.15
omn giver 60 point for svar | Giv et svar »

Formular med flere paramtre

Oprettet den 9. februar 2012 kl. 16.48
stuegnu giver 100 point for svar | Giv et svar »

Seneste guides

Installer win 7
Den gode bruger


   




Tips & Tricks fra PC World

Teaser billede

Her er fem sjove danske websider du skal kende

Trænger dine lattermuskler til en omgang fitness på dansk? Vi viser vej til fem websider fyldt med humor og vanvittig satire.


Anmeldelser fra PC World

Teaser billede

Test: Denne super-tablet er iPads hårdeste konkurrent

Eee Pad Transformer Prime er frygtindgydende med sin quadcore processor og evne til at trylle sig om til bærbar. Apple bør kigge i bagspejlet, for Asus' tablet-pc kommer buldrende - og gør det...


Seneste blogindlæg

Teaser billede

Tvangslukke spørgsmål: Hvad er den bedste løsning?

Hej Vi har mange åbne spørgsmål på Eksperten. Vi ville gerne tvangslukke dem - så et spørgsmål efter f.eks. 6 måneder lukkes. Men der er et par uklarheder som ville være gode at få lidt input til:...


Nyheder fra PC World

Teaser billede

Nu kan du snart hente Windows 8

Den nye offentlige betaversion af Windows 8 er klar i denne måned.


Nyheder fra Computerworld

Teaser billede

Måske snart slut med Androids helt store problem

Android-platformen har længe været plaget af et særligt problem. Men måske er problemet nu ved at være elimineret.


Kurser
Samarbejdspartnere

Udgiver · © 2012 IDG Danmark A/S · Hørkær 18 · 2730 Herlev · Tlf.: 77 300 300 · Fax: 77 300 301 · Brug af personoplysninger