WN

WN (https://www.wn.se/forum/index.php)
-   Serversidans teknologier (https://www.wn.se/forum/forumdisplay.php?f=4)
-   -   mySQL optimering (https://www.wn.se/forum/showthread.php?t=807)

danjel 2003-11-24 18:29

Hej!

Har lite problem med prestanda eller egentligen en allmän fundering kring denna typ av mysql frågor.
Nedanstående ska helt enkelt ta ut de 10 som senast har loggat in på ett system (tabellen inloggs ) och visa upp deras medlemsnamn som finns i en annan tabell (member)

SELECT
inloggs.*, member.user_name
FROM
inloggs, member
WHERE
inloggs.user_id=member.user_id
ORDER BY inloggs.id DESC
LIMIT 0,10

Denna tar ca 0.7 sekunder att exekvera,vilket i och för sig är godtagbart just nu men då innehåller inloggstabellen 120000 rader och members ca 6000 rader, inte speciellt mycket alltså....
(inloggs.user_id och member.user_id är indexerade, inloggs.id är auto increment)

Denna fråga går att optimera så här:

SELECT
inloggs.*, member.user_name
FROM
inloggs, member
WHERE
inloggs.user_id=member.user_id
AND inloggs.id > 119990
ORDER BY inloggs.id DESC
LIMIT 0,10


Alltså man hämtar först ut max värde för id och drar ifrån 10 , men det känns lite omständigt att behöva en extra query för detta..hur kan man annars göra ..någon som vet..?

Anders 2003-11-24 20:41

Citat:

Originally posted by danjel@Nov 24 2003, 16:29
Alltså man hämtar först ut max värde för id och drar ifrån 10 , men det känns lite omständigt att behöva en extra query för detta..hur kan man annars göra ..någon som vet..?
Ta och kolla lite på HAVING.
http://www.mysql.com/doc/en/SELECT.html
Eftersom du kan ha både HAVING och WHERE så borde det går i samma query. Sen kan du ju kolla lite på LEFT JOIN och UNION.

Tobbe 2003-11-25 00:21

Tror du ska ta dig en titt på JOINs...

ZN 2003-11-25 00:37

Observera att UNION inte stöds i versioner äldre än 4.

danjel 2003-11-26 12:11

Tack för era synpunkter. Kör inte mySQL 4 så varken union eller subqueries kan användas dessvärre...
Jag kan få det att funka med having men då tar det ca 4 sekunder :huh:

Anders 2003-11-27 17:04

Citat:

Ursprungligen postat av danjel
Tack för era synpunkter. Kör inte mySQL 4 så varken union eller subqueries kan användas dessvärre...
Jag kan få det att funka med having men då tar det ca 4 sekunder :huh:

Ok, hur lång tid tar det med JOIN då? Då kan du ju köra två frågor "samtidigt"...

Citat:

Ursprungligen postat av danjel
Nedanstående ska helt enkelt ta ut de 10 som senast har loggat in på ett system (tabellen inloggs ) och visa upp deras medlemsnamn som finns i en annan tabell (member)
[...]
då innehåller inloggstabellen 120000 rader och members ca 6000 rader [...]

Du kan inte rensa tabellen inloggs nån gång då och då? Detta snabbar ju upp sökningen då det inte är lika mycket data som ska sökas igenom. Dessutom kan du:
* istället för att skriva LIMIT 0,10 skriva bara LIMIT 10
* istället för att hämta inloggs.* bara hämta de fält du behöver; inloggs.user_id
Dessa två punkter gör inte så mycket, men sen när det blir ännu mer kommer det synas mer.

danjel 2003-11-27 18:02

Tack för sypunkterna lunne..
Citat:

Ok, hur lång tid tar det med JOIN då? Då kan du ju köra två frågor "samtidigt"...
..osäker på vad du menar, frågan använder ju redan en join..?

Ja att rensa tabellen,det har du rätt i, man bör nog rensa den rätt ofta...

Får ner det till 0.5 sekunder som bäst..
men boven i dramat är ORDER BY har jag märkt,
tar jag bort den tar frågan ca 0.025 sekunder...

Anders 2003-11-27 18:19

Citat:

Ursprungligen postat av danjel
Tack för sypunkterna lunne..

Så lite så, tycker ju det är intressant med optimering... :)

Citat:

Originally posted by -danjel@Nov 27 2003, 16:02
Citat:

Ok, hur lång tid tar det med JOIN då? Då kan du ju köra två frågor "samtidigt"...
..osäker på vad du menar, frågan använder ju redan en join..?

Jo, det var bara en tanke. Men jag tycker inte det blir riktigt rätt sätt att använda JOIN på, skit i det. Skulle dessutom vara slött...

Citat:

Originally posted by -danjel@Nov 27 2003, 16:02
Ja att rensa tabellen,det har du rätt i, man bör nog rensa den rätt ofta...
Jo, behöver du datan någon annanstans, eller går det sammanfatta i en annan tabell?

Citat:

Ursprungligen postat av danjel
Får ner det till 0.5 sekunder som bäst..
men boven i dramat är ORDER BY har jag märkt,
tar jag bort den tar frågan ca 0.025 sekunder...

Jo, men är det noga vem av de 10 som loggade in sist?

clindh 2003-12-01 14:09

Problemet tror jag är att du gör en descending order by - testa att sortera åt andra hållet och se om det hjälper. Med ditt lilla urval kan du ju alltid vända på ID:na i minnet sedan eller iterera resultatet baklänges.

I MySQL 4 skall det finnas ett sätt att bygga index så att de istället ordnas descending - men jag vet inte exakt hur...

Anders 2003-12-01 15:23

Citat:

Originally posted by clindh@Dec 1 2003, 12:09
Problemet tror jag är att du gör en descending order by - testa att sortera åt andra hållet och se om det hjälper. Med ditt lilla urval kan du ju alltid vända på ID:na i minnet sedan eller iterera resultatet baklänges.
Man tjänar sällan något på att sortera efter man fått ut datan från databasen, för MySQL i detta fall, är rätt snabb på det. Min erfarenhet säger mig att ASP och PHP är minst lika "slöa" på att sortera. Men man kan ju alltid prova. :)

clindh 2003-12-02 12:53

Jag läste på lite; det är bara när man sorterar på flera kolumner och blandar ASC och DESC som mySQL inte kan att använda befintliga index vid sorteringen. Men kör EXPLAIN på frågan vettja och se vad optimerarn tar för beslut.

Anders 2003-12-02 14:36

Citat:

Originally posted by clindh@Dec 2 2003, 10:53
Jag läste på lite; det är bara när man sorterar på flera kolumner och blandar ASC och DESC som mySQL inte kan att använda befintliga index vid sorteringen. Men kör EXPLAIN på frågan vettja och se vad optimerarn tar för beslut.
Jo, men har du nån aning om varför det tar så lång tid att sortera? Det är ju bara 10 rader, borde inte ta lång tid... :)

danjel 2003-12-02 15:31

Om man kör EXPLAIN (lite svårt att läsa detta ...):

Kod:

table type possible_keys key key_len ref rows Extra
inloggs index user_id PRIMARY 4 NULL 131535 
members eq_ref PRIMARY PRIMARY 3 inloggs.user_id 1

tror problemet är att ORDER BY körs på alla rader ,dvs 131535 st
men det konstiga är att order by på samma tabell utan en join går mycket snabbare..

Jag behöver alltså göra en order by i SQL eftersom jag endast vill ha ut dessa 10 rader och det måste vara ORDER BY DESC..annars får jag ut de första inloggningarna.

Anders 2003-12-02 22:50

Citat:

Ursprungligen postat av danjel
tror problemet är att ORDER BY körs på alla rader ,dvs 131535 st
men det konstiga är att order by på samma tabell utan en join går mycket snabbare..

Jo, men då är det JOIN som tar tid, inte ORDER BY.
Men man tycker det borde gå att göra så att den sorterar efter den hämtat ut rätt rader. Då har den ju inte lika mycket att sortera. Men det får man ju isf ta med MySQL AB... :)

Citat:

Ursprungligen postat av danjel
Jag behöver alltså göra en order by i SQL eftersom jag endast vill ha ut dessa 10 rader och det måste vara ORDER BY DESC..annars får jag ut de första inloggningarna.

Fanns det möjlighet att rensa lite i inloggs-tabellen? Det snabbar ju upp...

danjel 2003-12-03 17:09

nja, alltså frågan med join men utan order by går snabbt..typ:

"select * from inloggs,members where m.id=i.id limit 10"

och om jag kör typ:

"select * from inloggs order by id desc limit 10"

går också det snabbt på dessa 130 000 rader...

Men, så fort man lägger in en join med order by går det segt, kanske kör den order by på 130 000 * 6000 rader eller nåt skumt
(om du förstår den förklaringen ;) )

Anders 2003-12-04 16:04

Citat:

Originally posted by danjel@Dec 3 2003, 15:09
Men, så fort man lägger in en join med order by går det segt, kanske kör den order by på 130 000 * 6000 rader eller nåt skumt
(om du förstår den förklaringen ;) )

Hm, jo. Nåt konstigt är det. :)

Jaja, men frågan är om det går att snabba upp den där frågan ytterligare. Det är nog svårt eftersom den är så pass enkel, det går inte göra så mycket enklare...

void 2003-12-05 23:00

Ok,

nu är jag ute på tunn is och snurrar som bambi. Men om de båda frågorna går mycket snabbare enskilt, varför inte försöka och ställa dem för sig själva då? Har ingen aning om koden nedanför funkar, vet bara att jag gjort nåt liknande tidigare. Först skapar du en temporär tabell med de tio senaste inloggade och sen kör du en select där du klumpar ihop dem med användarna.

CREATE TEMPORARY TABLE senaste SELECT *FROM inlogg ORDER BY id DESC LIMIT 10;
SELECT * FROM members INNER JOIN senaste ON members.id = senaste.id;

eller ja, sista borde väl kanske gå lika bra med
SELECT FROM members,senaste WHERE members.id=senaste.id.

Hum, jag svamlar nog bara nu :rolleyes:

Anders 2003-12-06 01:03

Citat:

Originally posted by void@Dec 5 2003, 21:00
CREATE TEMPORARY TABLE senaste SELECT *FROM inlogg ORDER BY id DESC LIMIT 10;
SELECT * FROM members INNER JOIN senaste ON members.id = senaste.id;

eller ja, sista borde väl kanske gå lika bra med
SELECT FROM members,senaste WHERE members.id=senaste.id.

Hum, jag svamlar nog bara nu :rolleyes:

Jag har aldrig använt mig av TEMPORARY TABLE, men alla sätt är ju bra utom de dåliga... :)

Men frågan kvarstår om det blir nåt snabbare totalt sett? Varje fråga i sig kanske blir snabbare, men du får ju en del arbete mellan dem då istället som tar tid...

danjel 2003-12-08 15:12

Ja med en temporär tabell borde det gå snabbare..smart lösning
Egentligen var min ursprungliga fundering varför inte mySQL hanterar denna typ av frågor bättre, jag menar att ta ut de senaste posterna i en tabell och sen göra en join mot en annan tabell..det är väldigt 'basic' ,inte direkt en komplex fråga och jag tycker det borde funka utan en massa 'workarounds'


Alla tider är GMT +2. Klockan är nu 18:46.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson