Mysql
 sql >> Base de données >  >> RDS >> Mysql

Aide MySQL :Optimiser la requête de mise à jour qui définit le classement en fonction de l'ordre d'une autre colonne

Tout d'abord, je modifierais le budget , cost et rank_score en entier ou autre type de données numérique et au lieu de

UPDATE table_name
SET rank_score = CONCAT(cost, budget) ;

Ensuite, vous utiliserez :

UPDATE table_name
SET rank_score = cost * 1000 + budget * 1  ;

C'est plus facile alors car vous n'aurez pas à vous occuper des fonctions de chaîne et d'avoir quelque chose comme :

SELECT * 
FROM table_name
WHERE (conditions...)
ORDER BY rank_score DESC

(Parenthèse :ayant un paramètre (1000 ) mis plus haut que l'autre (1 ) équivaut à avoir une commande de cost, budget . Essayez ceci pour vérifier :

SELECT * 
FROM table_name
ORDER BY cost DESC
       , budget DESC

Donc, vous pouvez bien laisser tomber le rank_score tous ensemble, à moins bien sûr que vous ne prévoyiez de faire des expériences avec différentes valeurs de paramètres.

Comme d'autres l'ont souligné, il n'est pas recommandé d'avoir un champ qui ne stocke pas de données mais un calcul. C'est de la dénormalisation. Au lieu de cela, vous gardez la table normalisée et laissez la base de données faire les calculs chaque fois que vous en avez besoin :

SELECT id, budget, cost, 
       cost*1000 + budget*1 AS rank_score_calculated
FROM table_name
ORDER BY rank_score_calculated DESC

rank_score_calculated n'est pas stocké dans l'exemple ci-dessus. De cette façon, vous n'aurez pas à mettre à jour le champ calculé chaque fois qu'un budget ou un coût est modifié ou qu'une nouvelle ligne est ajoutée dans le tableau.

Il n'y a qu'un seul inconvénient. Si la table est vraiment grande et que vous avez besoin de cette requête (et du calcul) effectuée par de nombreux utilisateurs et très souvent, et que la table est mise à jour assez souvent, cela peut ralentir votre base de données. Dans ce cas, il faut commencer à penser à ajouter un tel champ.

L'autre cas est celui où l'on a besoin d'un rank absolu sur toutes les lignes du tableau, comme votre besoin. Parce que MySQL n'a pas de fonctions "fenêtres", il est très difficile d'écrire une telle requête en SQL pur.)

Le classement peut être calculé à l'aide de variables MySQL

SELECT *
     , @rownum:[email protected]+1 AS rank_calculated
FROM table_name
   , (SELECT @rownum:=0) AS st
ORDER BY rank_score DESC

Et si vous voulez mettre ces valeurs dans rank , utilisez :

UPDATE table_name
         JOIN
         ( SELECT id
                , @rownum:[email protected]+1 AS rank_calculated
           FROM table_name
              , (SELECT @rownum:=0) AS st
           ORDER BY rank_score DESC
         ) AS r
         ON r.id = table_name.id
SET table_name.rank = r.rank_calculated ;

Les deux requêtes ci-dessus ne sont pas du pur SQL. Vous pouvez examiner l'option de passer à un autre système de base de données qui prend en charge les fonctions de fenêtre, comme Postgres, SQL-Server ou Oracle.