phpMyAdmin
 sql >> Base de données >  >> Database Tools >> phpMyAdmin

Sélectionnez un enregistrement uniquement si celui qui le précède a une valeur inférieure prend trop de temps et échoue

Voici une solution pour votre question 1 qui s'exécutera beaucoup plus rapidement, car vous avez de nombreuses analyses de table complètes et des sous-requêtes dépendantes. Ici, vous n'aurez qu'un seul balayage de table (et peut-être une table temporaire, selon la taille de vos données et la quantité de mémoire dont vous disposez). Je pense que vous pouvez facilement l'adapter à votre question ici. La question 2 (je ne l'ai pas vraiment lue) est probablement également répondue car il est maintenant facile d'ajouter simplement where date_column = whatever

select * from (
    select
    t.*,
    if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,
    @prev_sn := SerialNumber,
    @prev_toner := Remain_Toner_Black
    from
    Table1 t
    , (select @prev_toner:=0, @prev_sn:=SerialNumber from Table1 order by SerialNumber limit 1) var_init
    order by SerialNumber, id
) sq  
where select_it = 1
  • le voir fonctionner en direct dans un sqlfiddle

MODIFIER :

Explication :

Avec cette ligne

    , (select @prev_toner:=0, @prev_sn:=SerialNumber from Table1 order by SerialNumber 

on initialise juste les variables @prev_toner et @prev_sn à la volée. C'est la même chose que de ne pas avoir cette ligne dans la requête mais d'écrire devant la requête

SET @prev_toner = 0;
SET @prev_sn = (select serialnumber from your_table order by serialnumber limit 1);
SELECT ...

Alors, pourquoi faire la requête pour attribuer une valeur à @prev_sn et pourquoi commander par numéro de série ? L'ordre par est très important. Sans ordre par, il n'y a pas d'ordre garanti dans lequel les lignes sont renvoyées. Nous accéderons également à la valeur des lignes précédentes avec des variables, il est donc important que les mêmes numéros de série soient "regroupés".

Les colonnes de la clause select sont évaluées les unes après les autres, il est donc important que vous sélectionniez d'abord cette ligne

if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,

avant de sélectionner ces deux lignes

@prev_sn := SerialNumber,
@prev_toner := Remain_Toner_Black

Pourquoi donc? Les deux dernières lignes affectent uniquement les valeurs des lignes actuelles aux variables. Donc dans cette ligne

if(@prev_toner < Remain_Toner_Black and @prev_sn = SerialNumber, 1, 0) as select_it,

les variables conservent toujours les valeurs des lignes précédentes. Et ce que nous faisons ici n'est rien de plus que de dire "si la valeur des lignes précédentes dans la colonne Remain_Toner_Black est plus petite que celle de la ligne actuelle et le numéro de série des lignes précédentes est le même que le numéro de série des lignes réelles, renvoie 1, sinon renvoie 0."

Ensuite, nous pouvons simplement dire dans la requête externe "sélectionner chaque ligne, où ce qui précède a renvoyé 1".

Compte tenu de votre requête, vous n'avez pas besoin de toutes ces sous-requêtes. Ils sont très chers et inutiles. En fait c'est assez dingue. Dans cette partie de la requête

    SELECT  a.ID, 
            a.Time, 
            a.SerialNumber, 
            a.Remain_Toner_Black,
            a.Remain_Toner_Cyan,
            a.Remain_Toner_Magenta,
            a.Remain_Toner_Yellow,
            (
                SELECT  COUNT(*)
                FROM    Reports c
                WHERE   c.SerialNumber = a.SerialNumber AND
                        c.ID <= a.ID) AS RowNumber
    FROM    Reports a

vous sélectionnez le tableau entier et pour chaque ligne vous comptez les lignes au sein de ce groupe. C'est une sous-requête dépendante. Tout simplement pour avoir une sorte de numéro de ligne. Ensuite, vous faites cela une deuxième fois, juste pour pouvoir joindre ces deux tables temporaires pour obtenir la ligne précédente. Vraiment, pas étonnant que les performances soient horribles.

Alors, comment ajuster ma solution à votre requête ? Au lieu de la seule variable que j'ai utilisée pour obtenir la ligne précédente pour Remain_Toner_Black, utilisez quatre pour les couleurs noir, cyan, magenta et jaune. Et rejoignez simplement la table des imprimeurs et des clients comme vous l'avez déjà fait. N'oubliez pas la commande par et vous avez terminé.