Avatar billede agf2413 Nybegynder
19. november 2014 - 13:18 Der er 10 kommentarer og
1 løsning

Optimering af sql statment

Jeg har to tables der er helt ens. Den ene hedder contacts og den anden doublets.

Jeg vil gerne i en sql statment søge alle igennem i contacts og se om der er nogle ens. De er ens hvis feltet 'firstName' er det samme. Hvis to eller flere er ens ønsker jeg at den kontakt med 'timeStamp' bliver i contacts og alle de andre bliver flyttet til doublets. Jeg har gjort dette på flere måde men da begge tabeller har rigtigt mange rows skal det optimeres så meget som muligt. Håber der er en som kan hjælpe med dette.

Mit sidste forsøg er dette:
INSERT INTO lcm_doublets(
    SELECT * FROM lcm_contacts WHERE `id` NOT IN (
        SELECT `id` FROM (   
            SELECT * FROM (
                SELECT * FROM lcm_contacts ORDER BY `timeStamp` ASC
            ) t1 GROUP BY `firstName`
        ) t2
    )
)
Dette virker men er alt for langsomt.
Opgaven haster så alt hjælp er værdsat!
19. november 2014 - 15:42 #1
Problemstillingen er mig desværre ikke helt tydelig.  Du siger, tror jeg, at hvis der i contacts tabellen er adskillige rækker med samme firstName, så vil du bevare den række med timeStamp, og de andre rækker skal indsættes i tabellen doublets og slettes i contacts.

Det at du taler om at bevare den kontakt med timeStamp, betyder det, at nogle rækker har feltet timeStamp fyldt ud, hvorimod i andre rækker timeStamp er tomt?  Og hvis der for eksempel er fire rækker med firstName 'Christian,' så vil en af rækkerne altid have en værdi i timeStamp og de andre tre rækker altid have en tom timeStamp?  Og at de kontakter hvoraf der ingen doublets er altid vil have en værdi i timeStamp?  Hvis det er tilfældet, så kan opgaven vel forenkles til at flytte alle rækker med en tom timeStamp til tabellen doublets.  Dette er næppe tilfældet, ellers ville du have løst det allerede, men hvordan skal det forstås, at du vil bevare den kontakt med timeStamp?
Avatar billede agf2413 Nybegynder
19. november 2014 - 15:51 #2
Tak for dit indlæg. Jeg skrev forkert. Der skulle stå den med MINDSTE timestamp. Så hvis vi har:

id  firstname        timeStamp(varchar)
1    Alex            2014-10-19 00:00:06
2    Alex            2014-10-18 00:00:06
3    Alex            2014-10-20 00:00:06

Så ønsker jeg at række 1 og 3 bliver rykket over i doublets men række 2 forbliver hvor den er da den har det laveste timestamp.
19. november 2014 - 17:26 #3
Men ihvorvel din kode indsætter dubletterne i doublets tabellen, så sletter den vist ikke dubletterne fra contacts tabellen.  Hvis det er en engangs opgave at sortere rækkerne i en tabel og du for fremtiden sørger for at holde contacts tabellen ren, så var det måske simplest at splitte contacts tabellen i to, contacts1 og doublets.  For eksempel noget i denne henretning (ikke testet), først

INSERT INTO contacts1
(SELECT * FROM contacts ORDER BY timeStamp ASC GROUP BY firstName)

og så

INSERT INTO doublets
(SELECT * FROM contacts WHERE id IN
    (SELECT id FROM contacts1)
)

og så slette contacts tabellen og derefter rename contacts1 til contacts.
Avatar billede agf2413 Nybegynder
19. november 2014 - 17:41 #4
Det er det svære ikke en engangsopgave.
Jeg kan godt oprette en table mere og gøre det på den måde. Men er det den hurtigste måde?
Er ikke så stærk i optimering af sql så lidt lost her. :)
Avatar billede agf2413 Nybegynder
19. november 2014 - 18:15 #5
Og hvis man gør det som du siger. Vil det så være en mulighed at lav en temorary table eller vil dette tage for lang tid til?
19. november 2014 - 20:07 #6
Om mit forslag er hurtigere kunne vel komme an på en prøve.  Men du siger, at koden i dit oprindelige spørgsmål virker.  Gør den mere end den ene opgave, indsætte dubletter i doublets tabellen?  Du vil jo også have dubletterne fjernet fra contacts tabellen.

Men hvis du ikke vil have dubletter i contacts tabellen, hvorfor bliver du så ved med at indsætte nye dubletter, således at du skal blive ved med bagefter at sortere dem?  Hvor bliver kontakter indsat i contacts tabellen?  Hvis du ændrede koden der, således at koden for hver ny kontakt checker, om contacts tabellen allerede har en med det pågældende firstName, og hvis den har, så placer den nye kontact i doublets med det samme.  Det ville i min mening være den bedste optimering, at holde orden i stedet for at skulle blive ved med at gøre orden.

Eller er det mig der ikke fatter en pind?
Avatar billede agf2413 Nybegynder
19. november 2014 - 22:28 #7
Igen tak for du gider hjælpe mig selvom jeg ikke forklare mig så godt.

Som du siger så vil det være mest optimalt at kontrollere inden man indsætter dem. Problemet ligger i at der bliver indsat "kontakter" i contacts hver dag. Disse kontakter kan ha en timestamp der er ændrer end dem der er i forvejen. Jeg kan derfor ikke blot kontrollere når man smider dem op.

I min første kode sletter jeg dem ikke fra contacts igen. Det gør jeg ved efterfølgende at køre:
DELETE FROM lcm_contacts WHERE id=ANY(SELECT `id` FROM lcm_doublets)

Jeg vil test det med en ekstra table og se om det er hurtigere lidt senere :)
19. november 2014 - 22:54 #8
Det afventer jeg så.
Men stadig, du siger, at der indsættes kontakter hver dag.  Så der må være en kode såsom INSERT INTO contacts ......  Der forestiller jeg mig, at du kunne kode, der checker om der allerede er en kontakt med det samme firstName.  Hvis ja, er timeStamp mindre end den nye timestamp, THEN insert den nye kontakt i doublets ELSE flyt den bestående komntakt til doublets AND insert den nye kontakt i contacts.  I så fald får du sat tingene i de rette tabeller fra starten, således at du undgår bestandigt at skulle sortere contacts.
Avatar billede agf2413 Nybegynder
20. november 2014 - 00:16 #9
Har du faktisk ret i. Hvis jeg konstant kontrollere med timestamp burde man jo kunne gøre det ved indlæsning. (Jeg er lidt langsom her, beklager)

Lyder som en noget bedre idé. Ser lige om jeg ikke kan gøre det sådan i stedet. Du kan blot smide et svar hvis du vil ha point. (ved ikke om man bruger er mere :P ) Du har været stor hjælp :)
Avatar billede arne_v Ekspert
20. november 2014 - 02:05 #10
Checke ved indsaet maa vaere det rigtige. Husk dog at sikre dig mod samtidigheds problemer - transaktion med hoejt transaction isolation level.

Hvis skal lave det som oprydniong saa ville jeg holde query helt simpel:

SELECT * FROM lcm_contacts ORDER BY  firstname ASC, timeStamp DESC

(med index paa baade firstname ASC og timeStamp)

Og saa lade applikationen haandtere check for dubletter, insert og delete.
20. november 2014 - 07:24 #11
Svar fra mig.  (Men måske vil du også invitere svar fra andre.)
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Computerworld tilbyder specialiserede kurser i database-management

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester