2012-12-20 4 views
4

Je dois sélectionner des enregistrements aléatoires de DB. Dans Sqlite3, que j'utilise en développement, il y a une fonction appelée Random(). Cependant, dans Postgresql, il s'appelle Rand(). Je ne me souviens pas de MySql, mais il s'appelle probablement ainsi.Sélection aléatoire pour différentes bases de données dans RoR

Donc, si j'ai un code de (pour Sqlite3)

data = Items.where(pubshied: is_pubshied).order("RANDOM()").limit(count) 

comment puis-je assurer que cela fonctionnera avec différentes bases de données?

+0

probablement lié http://stackoverflow.com/ questions/5342270/rails-3-get-random-record –

+0

J'ai ajouté ma réponse ci-dessous mais je devrais probablement dire que ta question est fausse car sqlite3 et postgresql utilisent 'random()' seulement mysql utilise 'rand()' –

+1

I Je pense plus à une solution de Railsy à votre problème, mais notez que vous venez de trouver la raison pour laquelle vous devriez utiliser le même système DB pour le développement et la production. Installer Postgres localement pour le développement; ça en vaut la peine. –

Répondre

4

Rails ne supporte pas ce hors de la boîte. Je crois que j'ai réalisé cela avec une extension de modèle (je ne l'utilise pas plus parce que je force l'utilisation de Postgresql), mais quelque chose comme cela pourrait fonctionner:

module Randomize 
    extend ActiveSupport::Concern 

    included do 
    scope :random, -> { order(rand_cmd) } 
    end 

    module ClassMethods 
    def rand_cmd 
     if connection.adapter_name =~ /mysql/i 
     'rand()' 
     else 
     'random()' 
     end 
    end 
    end 
end 

Vous pouvez alors faire

class Item 
    include Randomize 
end 

Item.where(...).random.limit(...) 
+0

Les implications en termes de performances sont un gros problème. Je ne peux pas imaginer que quelqu'un choisisse de faire quelque chose comme ça dans la production. – pguardiario

+0

@pguardiario Je ne vois pas pourquoi quelqu'un aurait besoin de l'utiliser dans la production de toute façon, cela dit .. implications de performance de quoi? Un appel de méthode? –

+0

Je veux dire les implications de performance de quelque chose comme 'order by rand()', qui, à moins que je ne me trompe, nécessitera une lecture complète du disque à chaque fois. – pguardiario

-1

De les commentaires de la poste que waldyr.ar mentionne dans son commentaire: https://stackoverflow.com/a/12038506/16784. Vous pouvez utiliser Items.all.sample(count). Bien sûr, cela récupère toute la table et peut ne pas être utile pour les grandes tables.

+1

C'est une mauvaise idée d'obtenir tous les éléments. –

+0

La commande par 'RAND()' est également horrible en général. Que cela soit utile dépend de l'utilisation prévue: pour les petites tables ou, plus probablement, pour les petites sélections de tables, la méthode 'sample' est très utile. Si la performance est essentielle, des stratégies plus élaborées sont nécessaires. C'est une solution pragmatique; Je répondrai volontiers à la question sur la façon d'augmenter les performances, si jamais cela arrive. – Confusion

0

Pour une manière performante, non spécifiques à l'adaptateur à l'ordre aléatoire, remplir une colonne aléatoire, mettre un index sur elle et l'appeler quelque chose comme:

Foo.order("random_column > #{rand}").limit(1) 
+0

Downvoting car cela vous donnera la même commande à chaque fois. Aussi, je * pense * qu'une fois que vous faites la soustraction, l'index ne sera pas utilisé, donc cela n'aide pas les performances. –

+0

Oui, ça devrait être un> je pense, de toute façon vous avez compris. – pguardiario

+0

Intéressant, mais je ne pense toujours pas que ce soit une très bonne solution: votre clause 'ORDER BY' évaluera à 'TRUE' pour certains des enregistrements, et' FALSE' pour les autres. Vous aurez toujours les valeurs les plus basses de 'random_column' venant plus près du début que du plus haut; Seul le point de coupure entre ces divisions sera aléatoire. Dans chaque division, la commande sera imprévisible. C'est à peine meilleur que pas de "ORDER BY" du tout, et peut même être pire, car il force les valeurs faibles de 'random_column' plus près du front, donc le caractère aléatoire sera plutôt biaisé. –

Questions connexes