Avatar billede websphere Nybegynder
29. juni 2006 - 05:47 Der er 15 kommentarer og
1 løsning

Find næste record

hejsa...

Jeg har en tabel der ser således ud:

fortløbende løbenummer
varenummer
f3
f4
f5
etc

Hvis jeg har fundet en vare baseret på varenummer vil jeg gerne kunne finde den næste, sorteret efter varenummer.
Varenumrene er unikke, men ikke fortløbende

Hvordan gør man det?
Avatar billede thrytter Nybegynder
29. juni 2006 - 08:19 #1
SELECT
  TOP 1 varenummer
FROM
  produkter
WHERE
  produkter.varenummer > @varenummer
ORDER BY
  produkter.varenummer DESC

Skulle udtrække næste varenummer større end det tidligere fundne (@varenummer)
Avatar billede websphere Nybegynder
29. juni 2006 - 08:21 #2
tak for svaret. jeg prøver det lige i morgen tidlig... Er i canada og her er kl. 23:30... men vender tilbage om en 6-7 timers tid...
Avatar billede nielle Nybegynder
29. juni 2006 - 08:24 #3
... eller:

SELECT
  Min(varenummer) AS nextVarenummer
FROM
  produkter
WHERE
  produkter.varenummer > @varenummer

Jeg gætter på at den er måske er mere effektiv idet den ikke skal sortere samtlige poster.
Avatar billede kjulius Novice
29. juni 2006 - 12:48 #4
... eller, som en udvidelse af nielles bidrag:

SELECT t1.varenummer, MIN(t2.varenummer) as NxtVarenummer
FROM produkter t1, produkter t2
WHERE t1.varenummer = ?
AND  t2.varenummer > t1.varenummer
GROUP BY t1.varenummer

Det skulle gerne give dig både det varenummer du søger og det næste i rækken...
Avatar billede websphere Nybegynder
29. juni 2006 - 16:05 #5
Men den skal vel stadig kun tage den første linje ikke, og hvis ikke det er sorteret vælger den så den der er en højere, eller vælger den næste i forhold til PK?
Avatar billede kjulius Novice
29. juni 2006 - 17:34 #6
Hvis der findes et index på feltet varenummer, er der sikkert ikke den store forskel på forslagene fra thrytter og nielle, da man må gå ud fra, at SQL server kan optimere søgningen, så der afbrydes når den første række efter den søgte er læst.

Hvis der ikke findes et index, vil thrytters metode sikkert kræve, at et sådant opbygges, da TOP instruktionen er baseret på en ordnet tabel.
Vha. nielles metode, KAN det måske være en fordel at gennemløbe rækkerne sekventielt og på denne måde finde det mindste varenummer, som samtidig er større end det søgte. Det afhænger af tabellens størrelse, og den afvejning (om det kan betale sig at opbygge et midlertidigt index), vil SQL server skulle gøre sig, når den laver sin execution plan.
Avatar billede websphere Nybegynder
29. juni 2006 - 17:41 #7
Vil det sige, at hvis der er oprettet et index så vil thrytters forslag være det bedste da den på forhånd vælger den rigtige ene linje?

Har jeg forstået dig ret?
Avatar billede nielle Nybegynder
29. juni 2006 - 17:43 #8
Koden 29/06-2006 08:19:32 kan finde næste *række* hvis den modificeres lidt:

SELECT
    TOP 1 *
FROM
    produkter
WHERE
    varenummer > @varenummer
ORDER BY
    varenummer DESC

Den bruger imidlertid en del resourcer på at sortere resten af posterne - arbejde som på en eller anden måde er spildt da du jo kun ønsker næste række og derfor er ligeglad med den næste i rækkefølgen eller den næste igen.


Hvis du derfor kun er interesseret i at kende det næste *varenummer*, hvilket no er det som den originale form gør:

SELECT
    TOP 1 varenummer
FROM
    produkter
WHERE
    varenummer > @varenummer
ORDER BY
    varenummer DESC

- ja, så kan den effektiviseres med Min()-funktionen (koden i 29/06-2006 08:24:46):

SELECT
    Min(varenummer) AS nextVarenummer
FROM
    produkter
WHERE
    varenummer > @varenummer
Avatar billede kjulius Novice
29. juni 2006 - 19:31 #9
Hmm... Ikke for at putte malurt i dit bæger, nielle, men jeg er nu ikke sikker på, at dit ræsonnement er helt rigtigt. Hvis SQL server er "dum", vil dit forslag med brug af MIN funktionen faktisk være langsommere. Forestil dig følgende situation:

Der findes et index på varenummer feltet.

1. SQL bruger indexet til at placere cursoren på rækken efter det søgte varenummer.
2. Herefter looper den de resterende rækker igennem og kalder for hver række MIN funktionen, som til sidst returnerer den mindste værdi.

Modsat med TOP 1:
1. SQL bruger indexet til at placere cursoren på rækken efter det søgte varenummer.
2. TOP 1 siger, at der kun skal returneres 1 række. Altså returneres værdien straks.


Jeg er klar over, at det er usandsynligt, at SQL server er så primitiv, at den ikke identificerer, at feltet der bruges i MIN funktionen i forvejen er sorteret i ASC orden via indexet, og at den første værdi derfor må være den laveste. Men kan man være sikker på det? Og er det i så fald ikke nøjagtig den samme kode der bliver eksekveret i begge tilfælde?
Er det overhovedet sikkert, at SQL server vil bruge indexet hvis det ikke er explicit angivet med en ORDER BY?
Avatar billede thrytter Nybegynder
30. juni 2006 - 08:26 #10
Lægger lige et svar
Avatar billede nielle Nybegynder
30. juni 2006 - 19:00 #11
Bare rolig, jeg tager såmæn ikke den slags ilde op. Man har vel lov til at lære noget nyt hele tiden.

Jeg forstår dog ikke rigtigt hvorfor at du som udgangspunkt mener at eksistensen af et indeks ikke også skulle effektivisere beregningen af Min(), og at den kun skulle slå igennem for TOP. Der er vel ingen grund til at databasen skulle loope igennem alle rækkerne for at finde den midste - når den jo ved at den allerede har sorteret dem i stigende orden?

Well, i stedet for at diskutere her fra til dommedag ... hvorfor så ikke bare måle efter? Så jeg lavede et eksperiment:

    1000 varer
    med unikke varerenumre i intervallet 0-9999

- og disse to SQL'er:

    1) SELECT TOP 1 varenummer FROM e718197 WHERE varenummer > 5000 ORDER BY varenummer DESC
    2) SELECT Min(varenummer) AS nextVarenummer FROM e718197 WHERE varenummer > 5000

For at kunne måle tiden, gentog jeg hver 10.000 gange. Disse målinger gentog jeg 5 gange. Databasen var en SQL Server 2005, den fulde version.

Uden index på varenummer (tiderne er i sekunder):

    1) 6,56 6,72 6,78 6,71 6,82
    2) 6,40 6,18 6,07 6,14 6,34

Her vinder 2) altså over 1) i effektivitet ... omend ikke med nogen overvældende margin.

Læg i iøvrigt mærke til at websphere aldrig har sagt at der er indeks på hans varenummer!

Det burde han måske overveje, for her er de samme målinger når man sætter index på varenummer:

    1) 1,42 1,56 1,54 1,67 1,59
    2) 2,36 2,48 2,33 2,52 2,38

Denne gang vinder 1) altså over 2) i effektivitet ... og jeg skal da være den første til at indrømme at marginen er noget mere overbevisende denne gang.

Men, for lige at få det sidste ord ind, så ses det tydeligt at indekset også har hjulpet på effektiviteten for Min()-versionen. :^)
Avatar billede kjulius Novice
30. juni 2006 - 22:01 #12
Tak for din indgangsvinkel. Jeg har desværre ikke haft mulighed for at teste mine teorier, så det er jo godt, at du har taget skraldet... ;-)

Jeg mener nu ikke på noget tidspunkt at have sagt, at eksistensen af et index ikke skulle effektivisere Min funktionen. Alene muligheden for at kunne placere cursoren på den søgte startrække som angivet i where sætningen, betyder jo, at Min funktionen kun behøver at behandle resten af rækkerne herfra, modsat situationen uden index, hvor den skal loope alle rækker igennem.

Faktisk kunne det dog være helt interessant, om ikke Min funktionen faktisk blev hurtigere uden index i en situation, hvor det søgte varenummer f.eks. blev sat til 1, således alt næsten alle rækker skulle behandles. I den situation ville alene det, at SQL skal bruge indexet under gennemløbet af de resterende rækker måske være en "bagdel". Under alle omstændigheder burde kløften mellem behandlingstiden for hhv. med og uden index være svundet en del ind i den situation.

Men konklusionen på dine tests må under alle omstændigheder være, at SQL server ikke er særlig "klog" mht. til at optimere en forespørgsel til at bruge indexet til andet end at placere cursoren. Den har jo helt tydeligt ikke indset, at da feltet Min funktionen bruges på er indexeret, er der ingen grund til at gennemløbe de resterende rækker, da den første værdi nødvendigvis må være den mindste.
Avatar billede websphere Nybegynder
03. juli 2006 - 16:07 #13
Hold da helt op.. Det blev en større undersøgelse vi der fik sat igang :)

Vil i ikke alle smide et svar, så fordeler jeg lige nogle point...

Og mange tak for hjælpen
Avatar billede kjulius Novice
06. juli 2006 - 00:51 #14
Ingen point til mig, tak. Jeg har kun gjort mig klog, og ikke kommet med noget nyt, så fordel du bare point mellem de andre...
Avatar billede nielle Nybegynder
06. juli 2006 - 06:56 #15
Tror at jeg springer over points på denne her. Jeg har alligevel fået noget meget mere værdifuldt ud af spørgsmålet (viden). Men ellers tak for tilbudet. :^)
Avatar billede websphere Nybegynder
06. juli 2006 - 07:28 #16
Ok - jamen i skal have mange tak for hjælpen ihvertfald....

God sommer
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