9
votes

Optimiser ma déclaration MySQL! - Rand () trop lent

J'ai donc une table avec plus de 80 000 enregistrements, celui-ci s'appelle le système. J'ai aussi une autre table appelée suit.

J'ai besoin de ma déclaration pour sélectionner au hasard des enregistrements à partir de la table du système, dans lequel cet identifiant n'est pas déjà répertorié dans le tableau suivant sous l'ID utilisateur actuel.

Voici donc ici Ce que j'ai: xxx

Il convient parfaitement, sauf que cela prend environ une minute entière avant de pouvoir commencer à traiter le travail à portée de main avec les enregistrements qu'elle a choisi. À ce moment-là, le script est habituellement de temps et que rien ne se passe.

Quelqu'un peut-il me montrer comment retravailler cela, alors la même idée est faite, mais elle n'utilise pas la commande par Rand? Cela semble ralentir une bouquet entière.

merci!


4 commentaires

Quels indices avez-vous sur vos champs de jointure? Cela peut être un grand cou de bouteille.


Je ne suis pas trop sûr de ce que tu veux dire ...


@Brandon Je sais que c'est un peu en retard pour cela, mais si vous voulez un moyen semi simpliste de le faire, vous pouvez simplement la mettre dans une sous-requête. Voir ma réponse ici pour plus de détails Stackoverflow.com / Questions / 25361158 / ...


Dupliqué possible de Comment optimiser l'ordre de MySQL par la fonction Rand () ?


6 Réponses :


7
votes

Je ne suis pas sûr qu'il y a une solution simple pour remplacer votre requête, voici un article sur la correction de ce type de problème.

http://www.titov.net/2005/09/21/Do-Not-Utilisateur-Orde-by-rand-or-how-to-get-Random-rows- de la table /


2 commentaires

Merci, mais ce n'est pas une option viable pour la façon dont cette requête fonctionne.


Pourquoi pas? Il y a beaucoup de solutions différentes dans cet article, dont certains, je pense travaillerait pour vous. Votre iD est-il un champ d'auto-crème? Si oui, la solution de sélection de IDS aléatoires devrait fonctionner.



2
votes

Vous pouvez générer une certaine valeur pseudo aléatoire en fonction des identifiants et de l'heure actuelle:

ORDER BY 37*(UNIX_TIMESTAMP() ^ system.id) & 0xffff


0 commentaires

2
votes

Il y a deux raisons principales de la lenteur:

  • SQL doit d'abord émettre un nombre aléatoire pour chacune des lignes
  • Les lignes doivent ensuite être commandées sur la base de ce numéro pour sélectionner les 200 top 200

    Il y a un tour pour aider cette situation, elle nécessite un peu de travail de préparation et la manière de la mettre en œuvre (et son intérêt relatif) dépend de votre cas d'utilisation réelle.

    = = = => Introduisez une colonne supplémentaire avec une valeur de "catégorie aléatoire" pour filtrer la plupart des lignes

    L'idée est d'avoir une colonne valorisée entière avec des valeurs attribuées au hasard, une fois au moment de la préparation, avec une valeur comprise entre dire 0 et 9 (ou 1 et 25 ... peu importe). Cette colonne doit ensuite être ajoutée à l'index utilisé dans la requête. Finaly, en modifiant la requête pour inclure un filtre sur cette colonne = une valeur particulière (par exemple 3), le nombre de lignes dont SQL doit fonctionner est ensuite réduit de 10 (ou 25, en fonction du nombre de valeurs distinctes que nous avons dans La "catégorie aléatoire".

    supposant que cette nouvelle colonne s'appelle RandPrefilter, nous pourrions introduire un index comme xxx

    et modifier la requête comme suit xxx


0 commentaires

5
votes

La raison pour laquelle la requête est lente, c'est que la base de données doit conserver une représentation de toutes les valeurs aléatoires générées et de leurs données respectives avant de pouvoir revenir même une seule ligne de la base de données. Ce que vous pouvez faire est de limiter le nombre de lignes candidates à considérer en premier à l'aide de l'endroit où Rand ()

Utilisation de cette approche permet à la base de données de traiter la requête de manière diffusée sans avoir à créer une grande représentation intermédiaire de toutes les données. L'inconvénient est que vous ne pouvez jamais être sûr à 100% que vous avez besoin du nombre d'échantillons dont vous avez besoin, vous devrez peut-être accomplir à nouveau la requête jusqu'à ce que vous le fassiez, vivez avec un échantillon plus petit ou d'ajouter progressivement des échantillons (en veillant à éviter les doubles cutanés. ) jusqu'à ce que vous ayez le nombre d'échantillons dont vous avez besoin.

Si vous n'avez pas besoin de la requête pour renvoyer différents résultats pour chaque appel, vous pouvez également ajouter une colonne de valeur aléatoire pré-générée avec un index et combiner avec la technique ci-dessus. Cela vous permettrait d'obtenir un nombre quelconque d'échantillons de manière équitable, même si vous ajoutez ou supprimez des lignes, mais la même requête sur les mêmes données retournerait bien sûr le même ensemble de résultats.


0 commentaires

1
votes

Selon la manière dont vos données doivent être aléatoires, il peut être utile de commander les données et d'ajouter une colonne DateTime supplémentaire "Dernière utilisation" et de la mise à jour une fois que vous utilisez les données. Ensuite, sélectionnez la commande Top N lignes par le dernier champ utilisé descensants.

Si vous enveloppez cela dans une instruction préparée, vous pouvez sélectionner un résultat aléatoire (semi) à la fois sans vous soucier de la logique.

Vous pouvez également donner à chaque ligne une carte séquentielle et générer le hasard dans le code et retirer les lignes requises. Le problème est que le jeu d'enregistrements complet est renvoyé avant d'être commandé.


0 commentaires

0
votes

Peut-être un peu tard, mais au moins ici est une solution supplémentaire pour la considération future: xxx

Premièrement, nous effectuons une sélection sur la table du système pour couper la table Minsystem et Minfollow Temp. Taille. Ensuite, nous sélectionnons des lignes aléatoires de la table Minfollows par la probabilité calculée. Aujourd'hui, nous aurons une table assez aléatoire de RandFollows pour rejoindre Minsystem. Enfin, nous limit 200.

Si vous utilisez Myisam, vous pouvez simplement récupérer la taille de la table. Cela élimine la sous-requête supplémentaire pour calculer le suit la taille de la table . Sinon, vous pouvez également coder le dénominateur si votre taille de table ne pousse pas trop vite (cela nécessite plus de maintenance manuelle).

Pour une explication plus approfondie, veuillez vérifier la solution que j'ai posté sur: MySQL: Alternatives à la commande par Rand ()

J'espère que cela aide (ou au moins j'espère que vous trouverez cela intéressant)!


0 commentaires