简体   繁体   中英

how to select n random rows in mysql from subset of large table?

I know there is this question that is very similar, but I wanted to add my specific situation and see if the answer is different.

I've read that you can simply do ORDER BY RAND() but that that is a bad idea for large tables. However, I can limit my rows to a max of about 160 with the WHERE clause. So the question is, is the WHERE clause evaluated and processed before the ORDER BY RAND(), thereby making this an acceptable solution?

My scenario is I'm implementing a card game. I have a deck table and a deck_card table. I'm trying to simply draw n random cards from the deck_cards table. Each game has a separate deck, so when a player draws n cards I know it is from a particular deck, so the proposed query is

select id
from deck_cards
where deck_id = ? and draw_pile = true
order by rand()
limit 5

The draw_pile column is for just what it sounds like, I keep track of where the cards are, in the draw_pile or discard_pile.

Incidentally, I'm doing this in rails and am trying to shuffle the results with Array.sort_by { rand } , but I'm seeing evidence that the rails rand isn't quite random. So another question is whether it is better to try the random function in the SQL or in rails. Currently, I don't have either the ORDER BY RAND or the Limit in the SQL. I'm shuffling the result array in rails and then just popping off n cards from that shuffled array. But again, I'm seeing results that indicate that the shuffle isn't really shuffling randomly.

The other issue/solution is perhaps table locking. This is a multiplayer, realtime game app. Occasionally I'm seeing >1 player drawing the same card. I assume this is from players drawing at the same time and hitting this query and shuffle which are somehow returning overlapping results.

"So the question is, is the WHERE clause evaluated and processed before the ORDER BY RAND(), thereby making this an acceptable solution?"

Yes.

The order by is only a cursor that say in what order the data should be retrieved from set.

I think using subquery will work as WHERE processed before the ORDER BY

select id
from deck_cards
where id in (select id
             from deck_cards
             where deck_id = ? and draw_pile = true
          )
order by rand()
limit 5

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM