2017-07-28 1 views
1

J'ai une requête assez simple (utilisée comme sous-requête dans une situation greatest-n-per-group). Le state_id est la clé primaire - tout le reste n'est pas unique.L'utilisation d'un filtre de plage dans une sous-requête de plus grand nombre par groupe a de très mauvaises performances

SELECT max(states.state_id) AS max_state_id 
FROM states 
WHERE states.created >= '2017-06-10 21:53:38.977455' 
    AND states.created < '2017-06-26 07:00:00' 
GROUP BY states.entity_id; 

Le problème est, cette requête est épouvantablement lent, et je ne crois pas pour l'indice multicolumn peut résoudre la façon dont il est écrit. Il finit toujours avec un using where; using index; using temporary; using filesort

Dans le cas où on ne sait pas: ce que nous essayons de faire ici est d'obtenir la dernière state_id pour chaque entity_id entre deux horodatages.

place, nous pourrions faire un max(states.created) (plutôt que max(states.state_id)) qui est probablement mieux de toute façon, mais je n'ai pas state_id pour la requête externe à se joindre à.

est ici la requête complète, y compris la partie extérieure pour donner tout le contexte:

SELECT states.state_id AS states_state_id, states.domain AS states_domain, states.entity_id AS states_entity_id, states.state AS states_state, states.attributes AS states_attributes, states.event_id AS states_event_id, states.last_changed AS states_last_changed, states.last_updated AS states_last_updated, states.created AS states_created 
FROM states INNER JOIN (
    SELECT max(states.state_id) AS max_state_id 
    FROM states 
    WHERE states.created >= '2017-06-10 21:53:38.977455' AND states.created < '2017-06-26 07:00:00' GROUP BY states.entity_id 
) AS anon_1 ON states.state_id = anon_1.max_state_id; 

Il doit sûrement y avoir un moyen de réécrire cette requête de manière à permettre un indice de faire un index en vrac de balayage ...

+0

Pourquoi la requête externe inclut-elle toutes les autres colonnes? En outre, votre requête 'MAX' pourrait être erronée si un' state_id' plus élevé ne signifie pas qu'il a été créé plus tard. –

+0

@FelixPamittan: bien, la requête externe renvoie simplement les valeurs dont l'application a besoin. Nous pourrions remplacer tout cela par 'select *' pour des raisons de concision. En ce qui concerne la création vs state_id, je suis d'accord et je l'ai mentionné dans ma question. Cependant, si nous n'obtenons pas le maximum de state_id, je ne suis pas sûr de la manière dont la requête externe s'y joindra – OverloadUT

+0

interrogez-vous la même période pour tous les 'id_utilisateur'? – Horaciux

Répondre

0

en premier lieu, pour cette requête:

SELECT max(s.state_id) AS max_state_id 
FROM states s 
WHERE s.created >= '2017-06-10 21:53:38.977455' AND 
     s.created < '2017-06-26 07:00:00' 
GROUP BY s.entity_id; 

Je veux être sûr que vous avez un index sur states(created, entity_d, state_id). Juste pour voir si cela aiderait.

En second lieu, envisager la réécriture de la requête comme:

SELECT max(s.state_id) AS max_state_id 
FROM states s 
WHERE s.created >= '2017-06-10 21:53:38.977455' AND 
     s.created < '2017-06-26 07:00:00' AND 
     s.state_id = (SELECT MAX(s2.state_id) 
        FROM states s2 
        WHERE s2.entity_id = s.entity_id AND 
          s2.created >= '2017-06-10 21:53:38.977455' AND 
          s2.created < '2017-06-26 07:00:00' 
        ); 

Pour cette requête, vous voulez des indices sur: states(entity_id, created, state_id) et states(created, entity_id, state_id) (l'ordre des colonnes dans les questions d'index).

+0

Malheureusement, le premier index ne fonctionne pas. Le problème est que la deuxième dimension est un filtre _range_ qui n'est pas groupé par, avec une fonction d'agrégation sur une troisième dimension. Cela rend impossible l'utilisation d'un index avec la manière dont la requête est actuellement écrite. En ce qui concerne la réécriture de la requête - je suis en train de tester cela ... – OverloadUT

+0

D'accord, cette deuxième requête ne semble pas fonctionner. En fait, je ne peux pas comprendre ce qu'il essaie de faire. Je peux dire que sans un index il a fonctionné pendant 13 heures qui me semble louche même si nous pouvons l'obtenir performant avec un index ?? – OverloadUT