Gå til innhold

Begrense antall stemmer til en per dag


Anbefalte innlegg

Videoannonse
Annonse
Prøve å bytte ut

LEFT OUTER JOIN `users` ON ( objects.object_user = users.user_id)

med

LEFT OUTER JOIN `users` ON ( votes.vote_user_id = users.user_id )

9531542[/snapback]

Spørringen returnerer akkurat de samme radene (i samme rekkefølge).

9532285[/snapback]

Hmm, dette er snedig. Synes å være en bug i implementasjonen av joins spør du meg. Hvilken versjon av MySQL er det du kjører dette på?

 

Det er et skudd i blinde, men du kan forsøke å bytte ut den andre left outer join med inner join. Det skal ikke ha noe å si for resultatet, men hvis det er en bug i implementasjonen av join så kan det være nok til å få det til å fungere som det skal, samt at det vel vil kunne være litt mer effektivt. Ellers begynner jeg å gå tom for ideer. Jeg har gjort tilsvarende på Microsoft SQL Server uten problemer.

Lenke til kommentar
Hmm, dette er snedig. Synes å være en bug i implementasjonen av joins spør du meg. Hvilken versjon av MySQL er det du kjører dette på?

 

Det er et skudd i blinde, men du kan forsøke å bytte ut den andre left outer join med inner join. Det skal ikke ha noe å si for resultatet, men hvis det er en bug i implementasjonen av join så kan det være nok til å få det til å fungere som det skal, samt at det vel vil kunne være litt mer effektivt. Ellers begynner jeg å gå tom for ideer. Jeg har gjort tilsvarende på Microsoft SQL Server uten problemer.

9532680[/snapback]

SELECT votes.vote_user_id, votes.vote_time, objects.object_id, objects.object_user, votes.vote_object_id, votes.vote_time
FROM `objects` LEFT OUTER JOIN `votes` ON ( objects.object_id = votes.vote_object_id )
INNER JOIN `users` ON ( votes.vote_user_id = users.user_id )
WHERE (
votes.vote_user_id = '100000008' AND DATE_FORMAT( NOW( ) , '%Y%m%d%H%i%S' ) - DATE_FORMAT( vote_time, '%Y%m%d%H%i%S' ) >=1000000
) OR votes.vote_user_id IS NULL

Returnerer object_id 100000010

 

 

SELECT votes.vote_user_id, votes.vote_time, objects.object_id, objects.object_user, votes.vote_object_id, votes.vote_time
FROM `objects` LEFT OUTER JOIN `votes` ON ( objects.object_id = votes.vote_object_id )
INNER JOIN `users` ON ( objects.object_user = users.user_id )
WHERE (
votes.vote_user_id = '100000008' AND DATE_FORMAT( NOW( ) , '%Y%m%d%H%i%S' ) - DATE_FORMAT( vote_time, '%Y%m%d%H%i%S' ) >=1000000
) OR votes.vote_user_id IS NULL

Returnerer object_id 100000004, 100000005, 100000006, 100000010

 

 

100000003 mangler derfor fortsatt. Jeg har brukt MySQL versjon 5.0.37, men prøvde nå å oppgradere til 5.0.45. Til tross for oppgraderingen, returnerer spørringene over de samme radene.

 

Om jeg ikke får til denne spørringen må jeg benytte meg av serialize() og en rad per bruker i tabellen votes. Dette er en løsning jeg ikke kan si at jeg er fornøyd med. Ved å måtte bruke unserialize() for hver spørring vil (etter hva jeg tror) mye resurser sløses bort.

 

Jeg fikk det nesten til ved å benytte meg av IF() i MySQL-spørringen:

SELECT 

IF(votes.vote_user_id = '100000008', '100000008', 'OTHER') AS if_vote_user_id, 

votes.vote_user_id, votes.vote_time, objects.object_id, objects.object_user, votes.vote_object_id, votes.vote_time
FROM `objects` LEFT OUTER JOIN `votes` ON ( objects.object_id = votes.vote_object_id )
LEFT OUTER JOIN `users` ON ( objects.object_user = users.user_id )

Men siden jeg ikke kan stille krav til verdier som er definert i selve spørringen, hjalp det lite.

Lenke til kommentar
Kan problemet skyldes de forskjellige tabellenes struktur/datasyper? Om det er slik som roac sier, at det er en bug som gjør at spørringen ikke fungerer, finnes det noen god måte å få rettet opp i denne bugen? Burde være av interesse også for de som står bak MySQL.

9557742[/snapback]

Hmm, jeg ser en issue her, men jeg må få stokket hodet mitt for å få den på plass. Det ER en en feil i where clausen, jeg må bare tenke litt på hvordan man kan komme rundt den på et fornuftig hvis (to subqueries kaller jeg ikke et fornuftig hvis :) )

Lenke til kommentar
Hmm, jeg ser en issue her, men jeg må få stokket hodet mitt for å få den på plass. Det ER en en feil i where clausen, jeg må bare tenke litt på hvordan man kan komme rundt den på et fornuftig hvis (to subqueries kaller jeg ikke et fornuftig hvis :) )

9559933[/snapback]

Da venter jeg i spenning. Har sett litt nærmere på where clausen min:

 

WHERE (
votes.vote_user_id = '100000008' AND DATE_FORMAT( NOW( ) , '%Y%m%d%H%i%S' ) - DATE_FORMAT( vote_time, '%Y%m%d%H%i%S' ) >=1000000
) OR votes.vote_user_id IS NULL

 

Som du ser setter spørringen et krav om at votes.vote_user_id må være lik 100000008 eller NULL. Det betyr jo at den ikke vil returnere objekter hvor votes.vote_user_id er lik noe annet enn 100000008. Siden bruker 100000000 har stemt på objektet 100000003, og bruker 100000008 ikke har gjort det, vil WHERE (

votes.vote_user_id = '100000008' AND ... gjøre objektet 100000003 til et "ugyldig" objekt, og det vil ikke returneres. Eller er jeg helt på jordet nå?

 

PS: Nærmere forklaring av spørring, se denne posten.

Lenke til kommentar

Disclaimer: Jeg leste bare førstesiden og skumleste den siste.

 

Her er min tanke om dette: Hvorfor ikke bruke Memcached? Raskt, enkelt og du trenger ikke tenke på opprydding i ettertid.

 

Litt usjekket kode:

 

if ( $mc->get( $userId + '-' + $objectId ) === false ) {
  $mc->set( $userId + '-' + $objectId, time(), 0, mktime( 0, 0, 0, date( 'm' ), date( 'd' ) + 1, date( 'Y' ) ) );
  //insert into datebase
}
else {
  //denne brukeren har allerede stemt på dette objektet dette døgnet
}

 

Du prøver altså å lage en key i memcached som identifiserer handlingen og dersom keyen finnes fra før betyr det at dette allerede er utført. Og dataene i memcached slettes av seg selv ved midnatt.

Endret av JohndoeMAKT
Lenke til kommentar
Disclaimer: Jeg leste bare førstesiden og skumleste den siste.

 

Her er min tanke om dette: Hvorfor ikke bruke Memcached? Raskt, enkelt og du trenger ikke tenke på opprydding i ettertid.

 

Litt usjekket kode:

 

if ( $mc->get( $userId + '-' + $objectId ) === false ) {
  $mc->set( $userId + '-' + $objectId, time(), 0, mktime( 0, 0, 0, date( 'm' ), date( 'd' ) + 1, date( 'Y' ) ) );
  //insert into datebase
}
else {
  //denne brukeren har allerede stemt på dette objektet dette døgnet
}

 

Du prøver altså å lage en key i memcached som identifiserer handlingen og dersom keyen finnes fra før betyr det at dette allerede er utført. Og dataene i memcached slettes av seg selv ved midnatt.

9560759[/snapback]

Memcached har jeg aldri hørt om. Vil den kun slette dataene ved midnatt, eller 24 timer etter at brukeren har gitt objektet en stemme? Om brukeren legger inn en stemme på objekt A kl. 23.30, skal ikke brukeren kunne stemme på det samme objektet før 23.30et døgn senere.

Lenke til kommentar

Memcached er en enkel minnecacheserver. Apache har en C++ skrevet PECL-modulklient som gjør at hastigheten er veldig god.

http://en.wikipedia.org/wiki/Memcached

 

I koden jeg skrev er det midnatt data blir slettet (egentlig flagget som utdatert og overskrevet neste gang plassen trengs), men det er bare å endre mktime-delen med en time() + 86400 for å holde dataene i akkurat ett døgn.

Lenke til kommentar
Jeg skal nå hente ut alle objekter som bruker_id 202 ikke har stemt på (gyldige objekter er 1000, 1001, 1002, 1004), og de objektene som bruker_id 202 har stemt på men hvor time <= 10000 (gyldige objekter er 1005). De objektene jeg skal sitte igjen med er dermed 1000, 1001, 1002, 1004 og 1005.

 

Utfra hva jeg har forstått skal du vise alle objekter hvor bruker x ikke har stemt de siste 10000 sekunder e.l.?

 

SELECT * from objects WHERE objects NOT IN (SELECT object_id FROM votes WHERE votes.user_id = X AND tid  > 10000)

 

Det er uinteressant å finne ut hvilke objekter han har stemt på for mer enn 10000 sekunder siden, eller hva den tiden nå blir satt til...

 

Spørringen burde være rimelig kjapp også, ettersom det er lite sannsynlig at man stemmer på titusenvis av objekter pr dag.

 

Ser dog ikke helt poenget med å hente ut alle objektene du skal kunne stemme på for å vise i en liste, det blir sikkert noen tusen etter hvert.

 

Hvis du bare skal sjekke om brukeren kan stemme på ett objekt så burde du bare sjekke om brukeren har stemt på det ene objektet de siste 10000 sekundene eller hva det nå var igjen ;)

 

Indeksen som blir brukt til å holde rede på timestamp kolonnen trenger strengt tatt ikke være en full indeks, det vil kun være de verdiene som er mindre enn x tid gamle som er interessante. Det vil derfor kanskje være en ide å recreate indeksen en gang i døgnet e.l. vil ikke indeksen på klokkeslett bli større enn de siste x tids rader.

 

Det kan også være en ide at timestamp indeksen er en multikolonneindeks på timestamp og brukerid, det vil i såfall være svært kjappt å finne hvilke objekter en bruker har postet på i det siste. Den vil ikke være spesiellt stor hvis den blir recreated en gang i døgnet av et script...

Endret av blackbrrd
Lenke til kommentar

Takk for hjelpen blackbrrd! Tror jeg har funnet en spørring som fungerer nå:

 

SELECT votes.vote_user_id, votes.vote_time, objects.object_id, objects.object_user, votes.vote_object_id, votes.vote_time
FROM `objects` LEFT OUTER JOIN `votes` ON ( objects.object_id = votes.vote_object_id )
LEFT OUTER JOIN `users` ON ( objects.object_user = users.user_id )
WHERE object_id NOT
IN (

SELECT vote_object_id
FROM votes WHERE votes.vote_user_id =100000008 AND DATE_FORMAT( NOW( ) , '%Y%m%d%H%i%S' ) - DATE_FORMAT( vote_time, '%Y%m%d%H%i%S' ) <=1000000
) AND object_user !=100000008
ORDER BY RAND() 
LIMIT 1

 

Mye unødvendig søvn som har gått til spille, spesielt med tanke på at løsningen var så "enkel"... Men det viktigste er at ting nå ser ut til å fungere. Takk til deg også, roac :)

 

 

Ser dog ikke helt poenget med å hente ut alle objektene du skal kunne stemme på for å vise i en liste, det blir sikkert noen tusen etter hvert.

Skal ikke hente ut en liste, men en tilfeldig rad fra resultatene.

Lenke til kommentar

Å sortere på RAND() er vel ikke nødvendigvis en god løsning?

 

Det kommer litt an på hvordan ORDER BY RAND() er implementert, men fant når jeg søkte vil ORDER BY RAND() generere ett random tall pr rad spørringen kan returnere, sortere resultatet på det tallet og med limit 1 returnere den første raden...

 

Problemet er når du har f.eks 1.000.000 objekter å velge random fra.. det kan ta sin tid :p

 

Løsning/beskrivelse av problemet:

http://jan.kneschke.de/projects/mysql/order-by-rand

http://people.planetpostgresql.org/greg/in...base-table.html

Endret av blackbrrd
Lenke til kommentar
Å sortere på RAND() er vel ikke nødvendigvis en god løsning?

 

Det kommer litt an på hvordan ORDER BY RAND() er implementert, men fant når jeg søkte vil ORDER BY RAND() generere ett random tall pr rad spørringen kan returnere, sortere resultatet på det tallet og med limit 1 returnere den første raden...

 

Problemet er når du har f.eks 1.000.000 objekter å velge random fra.. det kan ta sin tid :p

 

Løsning/beskrivelse av problemet:

http://jan.kneschke.de/projects/mysql/order-by-rand

http://people.planetpostgresql.org/greg/in...base-table.html

9567212[/snapback]

Har lest om dette tidligere. Er denne løsningen tilfredsstillende?

Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
×
×
  • Opprett ny...