J'optimise beaucoup de requêtes existantes dans mon projet. La solution de Quassnoi m'a beaucoup aidé à accélérer les requêtes! Cependant, j'ai du mal à incorporer ladite solution dans toutes les requêtes, en particulier pour les requêtes compliquées impliquant de nombreuses sous-requêtes sur plusieurs grandes tables.
J'utilise donc une solution moins optimisée. Fondamentalement, cela fonctionne de la même manière que la solution de Quassnoi.
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor / [accomodation_table_row_count]
LIMIT $size
$size * $factor / [accomodation_table_row_count]
calcule la probabilité de choisir une ligne aléatoire. Le rand () générera un nombre aléatoire. La ligne sera sélectionnée si rand () est plus petit ou égal à la probabilité. Cela effectue effectivement une sélection aléatoire pour limiter la taille de la table. Puisqu'il y a une chance qu'il renvoie moins que le nombre limite défini, nous devons augmenter la probabilité pour nous assurer que nous sélectionnons suffisamment de lignes. Par conséquent, nous multiplions $ size par un $ factor (je fixe généralement $ factor = 2, fonctionne dans la plupart des cas). Enfin nous faisons lelimit $size
Le problème est maintenant de travailler sur l' accomodation_table_row_count . Si nous connaissons la taille de la table, nous pourrions coder en dur la taille de la table. Ce serait le plus rapide, mais ce n'est évidemment pas l'idéal. Si vous utilisez Myisam, obtenir le nombre de tables est très efficace. Depuis que j'utilise innodb, je ne fais qu'un simple comptage + sélection. Dans votre cas, cela ressemblerait à ceci:
SELECT accomodation.ac_id,
accomodation.ac_status,
accomodation.ac_name,
accomodation.ac_status,
accomodation.ac_images
FROM accomodation, accomodation_category
WHERE accomodation.ac_status != 'draft'
AND accomodation.ac_category = accomodation_category.acat_id
AND accomodation_category.acat_slug != 'vendeglatohely'
AND ac_images != 'b:0;'
AND rand() <= $size * $factor / (select (SELECT count(*) FROM `accomodation`) * (SELECT count(*) FROM `accomodation_category`))
LIMIT $size
La partie la plus délicate consiste à déterminer la bonne probabilité. Comme vous pouvez le voir, le code suivant ne calcule en fait que la taille approximative de la table temporaire (en fait, trop approximative!): (select (SELECT count(*) FROM accomodation) * (SELECT count(*) FROM accomodation_category))
Mais vous pouvez affiner cette logique pour donner une approximation plus proche de la taille de la table. Notez qu'il vaut mieux sur-sélectionner que sous-sélectionner des lignes. c'est-à-dire que si la probabilité est trop faible, vous risquez de ne pas sélectionner suffisamment de lignes.
Cette solution fonctionne plus lentement que la solution de Quassnoi car nous devons recalculer la taille de la table. Cependant, je trouve ce codage beaucoup plus gérable. Il s'agit d'un compromis entre précision + performances et complexité de codage . Cela dit, sur les grandes tables, c'est encore beaucoup plus rapide que Order by Rand ().
Remarque: Si la logique de requête le permet, effectuez la sélection aléatoire le plus tôt possible avant toute opération de jointure.