[SQL]Refactoren lelijke query; query leesbaarder maken

Pagina: 1
Acties:

Onderwerpen


Acties:
  • 0 Henk 'm!

  • van.der.schulting
  • Registratie: Juli 2002
  • Laatst online: 09-08-2024
Ik heb de volgende query:
code:
1
SELECT * FROM media WHERE id IN (SELECT id FROM media ORDER BY RAND() LIMIT 15) ORDER BY title

Helaas werkt deze query niet. Aangezien MYSQL geen LIMIT ondersteunt in een subquery, moest ik hem een beetje herschrijven mbv deze post. Dit resulteerde hierin:
code:
1
SELECT * FROM media WHERE id IN (SELECT * FROM (SELECT id FROM media ORDER BY RAND() LIMIT 15)alias) ORDER BY title

Anyhow, wat ik in feite wil is van is dus uit de tabel media 15 willekeurige records halen en deze vervolgens sorteren op title.

Toegegeven, dat lukt gewoon met bovenstaande query, maar ik vind deze query moeilijk te begrijpen. De eerste query is al een stuk beter te begrijpen, maar werkt helaas niet en ik vind ook de eerste query niet bepaald ideaal.

Kortom kan ik deze query wat 'leesbaarder' / simpeler maken? Het liefst zonder subquery.

Acties:
  • 0 Henk 'm!

  • TRON
  • Registratie: September 2001
  • Laatst online: 09:03
Heb je deze query al geprobeerd?
code:
1
SELECT * FROM media ORDER BY RAND() LIMIT 15;

Leren door te strijden? Dat doe je op CTFSpel.nl. Vraag een gratis proefpakket aan t.w.v. EUR 50 (excl. BTW)


Acties:
  • 0 Henk 'm!

  • van.der.schulting
  • Registratie: Juli 2002
  • Laatst online: 09-08-2024
Heb ik niks aan, want dan sorteer je niet op title. Zoals ik al aangaf, ik wil 15 willekeurige records pakken en deze vervolgens sorteren op title.

Acties:
  • 0 Henk 'm!

  • OnTracK
  • Registratie: Oktober 2002
  • Laatst online: 13:14
Waarom doe je dit niet?

SQL:
1
2
3
4
5
6
7
8
SELECT *
FROM (
    SELECT * 
    FROM media 
    ORDER BY RAND() 
    LIMIT 15
) alias
ORDER BY title
Lijkt me ook nog effiiënter dan je eerste optie.

Not everybody wins, and certainly not everybody wins all the time.
But once you get into your boat, push off and tie into your shoes.
Then you have indeed won far more than those who have never tried.


Acties:
  • 0 Henk 'm!

  • Raymond P
  • Registratie: September 2006
  • Nu online
ehm?

edit: <knip> (ik ga slapen)

Maar ik denk dat je RAND() misschien beter in je code af kan handelen :P

[ Voor 34% gewijzigd door Raymond P op 22-03-2011 00:34 ]

- knip -


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

OnTracK schreef op dinsdag 22 maart 2011 @ 00:01:
Waarom doe je dit niet?

SQL:
1
2
3
4
5
6
7
8
SELECT *
FROM (
    SELECT * 
    FROM media 
    ORDER BY RAND() 
    LIMIT 15
) alias
ORDER BY title
Lijkt me ook nog effiiënter dan je eerste optie.
Precies. :) Dat LIMIT niet werkt in subqueries klopt namelijk niet: het werkt niet in IN/ANY/ALL/SOME-subqueries. Wanneer je select uit de resultset van een subquery kun je dus gewoon een limit gebruiken, wat ook de reden is dat je dubbele subquery werkt.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • van.der.schulting
  • Registratie: Juli 2002
  • Laatst online: 09-08-2024
Thanks, dat scheelt idd. Alleen toch jammer dat ik het met een subquery moet oplossen :(

Had stiekem gehoopt dat het zonder kon.

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Waarom? Wat maakt een subquery nou uit? Deze query is maar marginaal langzamer dan alleen de subquery zou zijn en bovendien prima leesbaar. Wat wil je nog meer?

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • van.der.schulting
  • Registratie: Juli 2002
  • Laatst online: 09-08-2024
Het had op een wat nettere manier binnen het model (MVC) gepast als het geen subquery was geweest.
Verder is het idd een beetje mierenneuken ;)

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

MVC legt helemaal geen restricties aan hoe diep je queries nesten? :P

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • van.der.schulting
  • Registratie: Juli 2002
  • Laatst online: 09-08-2024
Klopt als een bus, maar ik had het het liefst als volgt opgelost
code:
1
Model.find ....


In plaats van nu dus
code:
1
2
3
4
5
class Model {
  function find_fifteen_titles() {
    return query "SELECT * FROM ( SELECT * FROM media ORDER BY RAND() LIMIT 15) alias ORDER BY title"
  }
}

Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

PHP:
1
2
3
4
5
6
class Model {
  function find($amount) {
    $amount = (int)$amount;
    return query "SELECT * FROM ( SELECT * FROM media ORDER BY RAND() LIMIT {$amount}) alias ORDER BY title"
  }
}

:?

En hoe je query eruit ziet boeit voor deze functie natuurlijk ook niks, of het nou met subquery is of zonder. ;)

[ Voor 22% gewijzigd door NMe op 22-03-2011 21:49 ]

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • fleppuhstein
  • Registratie: Januari 2002
  • Laatst online: 07-09 13:37
SQL:
1
2
3
4
5
6
  SELECT *
    FROM media 
    ORDER BY 
      RAND(),
      title 
    LIMIT 15


Er is toch niks mis met primair order op de rand, om zo het willekeurig gedeelte op te lossen, en vervolgens op de title, gelijk de subquery verdwenen.

Acties:
  • 0 Henk 'm!

  • hostname
  • Registratie: April 2009
  • Laatst online: 10:59
fleppuhstein schreef op dinsdag 22 maart 2011 @ 21:50:
SQL:
1
2
3
4
5
6
  SELECT *
    FROM media 
    ORDER BY 
      RAND(),
      title 
    LIMIT 15


Er is toch niks mis met primair order op de rand, om zo het willekeurig gedeelte op te lossen, en vervolgens op de title, gelijk de subquery verdwenen.
Alleen gaat dat niet werken. Elk item krijgt namelijk een andere waarde voor de RAND(), waardoor ze daar al op gesorteerd staat en ze niet meer op titel gesorteerd worden. Dit zou alleen werken mochten de eerste 15 items dezelfde waarde voor de RAND hebben.

Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
Wel weer zo'n echte MySQL-only oplossing; los van de syntax zou dit op MSSQL en AFAIK ook op Postgre en Oracle niet werken omdat de order by de rand maar 1 keer zou aanroepen en dus voor alle records dezelfde value returnen.
Euh, wacht effe... knik in m'n brein even uitstrijken :P
Nee, klopt toch min-of-meer wat ik zeg :Y) Dit geldt in ieder geval voor MSSQL. En daarbij is zo'n query in de meeste RDBMS'en (en dus ook MySQL) waarschijnlijk duur want het zal een full table scan als gevolg hebben om voor elke row een rand() te genereren.

[ Voor 57% gewijzigd door RobIII op 22-03-2011 22:26 ]

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

RobIII schreef op dinsdag 22 maart 2011 @ 22:14:
Wel weer zo'n echte MySQL-only oplossing; los van de syntax zou dit op MSSQL en AFAIK ook op Postgre en Oracle niet werken omdat de order by de rand maar 1 keer zou aanroepen en dus voor alle records dezelfde value returnen.
Euh, wacht effe... knik in m'n brein even uitstrijken :P
Nee, klopt toch min-of-meer wat ik zeg :Y) Dit geldt in ieder geval MSSQL. En daarbij is zo'n query in de meeste RDBMS'en (en dus ook MySQL) waarschijnlijk duur want het zal een full table scan als gevolg hebben om voor elke row een rand() te genereren.
LIMIT werkt sowieso niet in andere DBMS'en dan MySQL. :)

Verder: zelfs als het met ordering goed zou gaan als je subquery en main query omwisselt, dan nog zit je met een veel grotere resultset, dat performeert vast niet.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • RobIII
  • Registratie: December 2001
  • Niet online

RobIII

Admin Devschuur®

^ Romeinse Ⅲ ja!

(overleden)
NMe schreef op dinsdag 22 maart 2011 @ 22:26:
[...]

LIMIT werkt sowieso niet in andere DBMS'en dan MySQL. :)
Het ging mij om de Rand(), maar die blijkt in de meeste RDBMS'en ondersteund (ook MSSQL, dat wist ik niet; ik gebruik 't dan ook nooit :P )

There are only two hard problems in distributed systems: 2. Exactly-once delivery 1. Guaranteed order of messages 2. Exactly-once delivery.

Je eigen tweaker.me redirect

Over mij


Acties:
  • 0 Henk 'm!

  • van.der.schulting
  • Registratie: Juli 2002
  • Laatst online: 09-08-2024
NMe schreef op dinsdag 22 maart 2011 @ 21:48:
En hoe je query eruit ziet boeit voor deze functie natuurlijk ook niks, of het nou met subquery is of zonder. ;)
Ik was wat onvolledig; ik werk met CakePHP. De functie Model.find is een standaard functie van CakePHP. Die kan ik dus niet gebruiken. Met jou oplossing override ik die functie ;)
Daarvoor heb ik de functie Model.query nodig..

Anyhow, eigenlijk nutteloze details :P

Acties:
  • 0 Henk 'm!

  • Camulos
  • Registratie: Januari 2009
  • Laatst online: 06-09 22:59

Camulos

Stampert

Houdt wel rekening mee dat de rand() functie in MySQL op een hele tabel echt langzaam werkt.
SQL:
1
2
ORDER BY RAND()
LIMIT 15


Hij zal eerst de hele tabel randomnizen en vervolgens de eerste 15 pakken.
Wanneer je tabel (tien)duizenden rijen bevat .. dan kan dit soms lang duren (denk aan seconden afhankelijk van het systeem).

Had dit probleem laatst een keer... had mijn query minstens 1000x sneller gemaakt door zelf random getallen te maken en deze in de WHERE-clause te zetten. Hiermee elimineer je de order-by en de limit :)

SQL:
1
WHERE primary-id = X OR primary-id = Y OR primary-id = Z

[ Voor 7% gewijzigd door Camulos op 23-03-2011 08:44 ]

Not just an innocent bystander


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Camulos schreef op woensdag 23 maart 2011 @ 08:42:
Houdt wel rekening mee dat de rand() functie in MySQL op een hele tabel echt langzaam werkt.
SQL:
1
2
ORDER BY RAND()
LIMIT 15


Hij zal eerst de hele tabel randomnizen en vervolgens de eerste 15 pakken.
Wanneer je tabel (tien)duizenden rijen bevat .. dan kan dit soms lang duren (denk aan seconden afhankelijk van het systeem).

Had dit probleem laatst een keer... had mijn query minstens 1000x sneller gemaakt door zelf random getallen te maken en deze in de WHERE-clause te zetten. Hiermee elimineer je de order-by en de limit :)

SQL:
1
WHERE primary-id = X OR primary-id = Y OR primary-id = Z
Maar dat werkt natuurlijk alleen als je weet dat al je id's sequentieel achter elkaar liggen zonder gaten ertussen.

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Camulos
  • Registratie: Januari 2009
  • Laatst online: 06-09 22:59

Camulos

Stampert

@Woy: idd... ik ga ervan uit dat er geen/weinig gaten zijn.

Wil je dat tegen gaan kun je bijvoorbeeld 20 random waarden nemen en dan limiten op 15 (maar dit werkt idd maar tot op zekere hoogte)

[ Voor 200% gewijzigd door Camulos op 23-03-2011 09:43 . Reden: In eerste instantie verkeerd geinterpreteerd ]

Not just an innocent bystander


Acties:
  • 0 Henk 'm!

  • kwaakvaak_v2
  • Registratie: Juni 2009
  • Laatst online: 02-06 12:29
van.der.schulting schreef op woensdag 23 maart 2011 @ 00:28:
[...]


Ik was wat onvolledig; ik werk met CakePHP. De functie Model.find is een standaard functie van CakePHP. Die kan ik dus niet gebruiken. Met jou oplossing override ik die functie ;)
Daarvoor heb ik de functie Model.query nodig..

Anyhow, eigenlijk nutteloze details :P
Dus jij beweert dat je in cake niet de Model kan extenden met een eigen class en dan een myModel.find() kan uitvoeren..

Driving a cadillac in a fool's parade.


Acties:
  • 0 Henk 'm!

  • Killemov
  • Registratie: Januari 2000
  • Laatst online: 24-08 23:40

Killemov

Ik zoek nog een mooi icooi =)

NMe schreef op dinsdag 22 maart 2011 @ 22:26:
[...]

LIMIT werkt sowieso niet in andere DBMS'en dan MySQL. :)
NIET waar. Beetje vervelend als een admin een leugen verkondigt.

Hey ... maar dan heb je ook wat!


Acties:
  • 0 Henk 'm!

  • djexplo
  • Registratie: Oktober 2000
  • Laatst online: 07-07 15:40
Killemov schreef op donderdag 24 maart 2011 @ 09:48:
[...]
NIET waar. Beetje vervelend als een admin een leugen verkondigt.
WEL waar ;). (MS SQL en Oracle SQL kennen limit b.v. niet)

Heb jij een bron, voorbeeld? (Zelf al gevonden PostgreSQL)

[ Voor 5% gewijzigd door djexplo op 24-03-2011 09:56 . Reden: Google ]

'if it looks like a duck, walks like a duck and quacks like a duck it's probably a duck'


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

Killemov schreef op donderdag 24 maart 2011 @ 09:48:
[...]

NIET waar. Beetje vervelend als een admin een leugen verkondigt.
Beetje vervelend om voor leugenaar uitgemaakt te worden als a) het aannemelijk is dat er geen opzet in het spel is, b) admins ook mensen zijn en c) je niet vertelt waarom je denkt dat ik lieg.

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Killemov
  • Registratie: Januari 2000
  • Laatst online: 24-08 23:40

Killemov

Ik zoek nog een mooi icooi =)

NMe schreef op donderdag 24 maart 2011 @ 10:40:
[...]

Beetje vervelend om voor leugenaar uitgemaakt te worden als a) het aannemelijk is dat er geen opzet in het spel is, b) admins ook mensen zijn en c) je niet vertelt waarom je denkt dat ik lieg.
Postgres kent het in ieder geval.

Je had de opmerking niet hoeven plaatsen. Als je niet de waarheid vertelt (opzet of niet) dan ... lieg je. En als admin, inderdaad ook maar een mensch, leg je daarbij nogal wat gewicht in de schaal.

Hey ... maar dan heb je ook wat!


Acties:
  • 0 Henk 'm!

Verwijderd

Killemov schreef op donderdag 24 maart 2011 @ 11:03:
[...]
Als je niet de waarheid vertelt (opzet of niet) dan ... lieg je.
lie·gen loog, h gelogen met opzet onwaarheden spreken: hij liegt dat hij barst heel erg; dat liegt er niet om dat moet je niet onderschatten

Overigens is alhier een mooie lijst van dit soort verschillen tussen DBMS'en. Postgres en MySQL zijn kennelijk de enige DBMS'en die LIMIT kennen.

[ Voor 22% gewijzigd door Verwijderd op 24-03-2011 13:01 ]


Acties:
  • 0 Henk 'm!

  • NMe
  • Registratie: Februari 2004
  • Laatst online: 09-09 13:58

NMe

Quia Ego Sic Dico.

offtopic:
Gelukkig is alwetendheid geen requirement voor een functie als admin op een forum. :)

'E's fighting in there!' he stuttered, grabbing the captain's arm.
'All by himself?' said the captain.
'No, with everyone!' shouted Nobby, hopping from one foot to the other.


Acties:
  • 0 Henk 'm!

  • Killemov
  • Registratie: Januari 2000
  • Laatst online: 24-08 23:40

Killemov

Ik zoek nog een mooi icooi =)

Verwijderd schreef op donderdag 24 maart 2011 @ 12:58:
[...]
lie·gen loog, h gelogen met opzet onwaarheden spreken: hij liegt dat hij barst heel erg; dat liegt er niet om dat moet je niet onderschatten

Overigens is alhier een mooie lijst van dit soort verschillen tussen DBMS'en. Postgres en MySQL zijn kennelijk de enige DBMS'en die LIMIT kennen.
Sow, Oracle maakt er echt een crypto-hit van. En de standaard gewoon he-le-maal niet ondersteunen he.

Hey ... maar dan heb je ook wat!


Acties:
  • 0 Henk 'm!

  • Woy
  • Registratie: April 2000
  • Niet online

Woy

Moderator Devschuur®
Killemov schreef op donderdag 24 maart 2011 @ 22:40:
[...]

Sow, Oracle maakt er echt een crypto-hit van. En de standaard gewoon he-le-maal niet ondersteunen he.
Je kan natuurlijk meteen hoog van de toren blazen, en iemand voor een leugenaar uitmaken. Je kan natuurlijk ook gewoon zeggen dat er nog meer RDBMS'en zijn die het wel ondersteunen, maar dat het geen onderdeel van de SQL standaard is, en dat er meer systemen zijn die het niet ondersteunen dan wel ( Al zal het merendeel van de systemen wel een dergelijk mechanisme kennen ).

“Build a man a fire, and he'll be warm for a day. Set a man on fire, and he'll be warm for the rest of his life.”


Acties:
  • 0 Henk 'm!

  • Voutloos
  • Registratie: Januari 2002
  • Niet online
Oracle de schuld geven is tevens ook niet correct (een leugen :+ ), want LIMIT zat er al jaren in. ;)

{signature}


Acties:
  • 0 Henk 'm!

  • PrisonerOfPain
  • Registratie: Januari 2003
  • Laatst online: 26-05 17:08
Camulos schreef op woensdag 23 maart 2011 @ 08:42:
Hij zal eerst de hele tabel randomnizen en vervolgens de eerste 15 pakken.
Wanneer je tabel (tien)duizenden rijen bevat .. dan kan dit soms lang duren (denk aan seconden afhankelijk van het systeem).
Beetje jammer dat de optimizer dit niet begrijpt en gewoon random N elementen uit de index trekt.

Acties:
  • 0 Henk 'm!

  • barfieldmv
  • Registratie: Maart 2004
  • Laatst online: 23-08 21:37
Ik zou vanuit de code een select id from tablename doen en die cachen (elke paar minuten updaten)
Vervolgens vanuit de code een random lijstje uit de id list pakken en dan dan 15 querien.

Met een cache dependency kan je je cache bij een data wijziging droppen en je kan je lijstje desnoods uitbreiden met de 15 laatste items voor als je hele random lijstje een keertje niet meer bestaat.

Dit stelt je meteen in staat om in de toekomst slimmere 'pak 15 willekeurige items' te pakken zodat er niet 2 keer achter elkaar dezelfde 'random' items in de lijst staan etc.
Pagina: 1