Vous ne voulez probablement pas entendre cela, mais la meilleure option pour accélérer SELECT DISTINCT
est d' éviter DISTINCT
de commencer. Dans de nombreux cas (pas tous!), Cela peut être évité avec une meilleure conception de la base de données ou de meilleures requêtes.
Parfois, GROUP BY
c'est plus rapide, car cela prend un chemin de code différent.
Dans votre cas particulier , il ne semble pas que vous puissiez vous en débarrasser DISTINCT
. Mais vous pouvez prendre en charge la requête avec un index spécialisé si vous avez de nombreuses requêtes de ce type:
CREATE INDEX foo ON events (project_id, "time", user_id);
L'ajout user_id
n'est utile que si vous obtenez des analyses d'index uniquement . Suivez le lien pour plus de détails. Supprime le scan de tas Bitmap coûteux de votre plan de requête, qui consomme 90% du temps de requête.
Votre EXPLAIN
résultat me dit que la requête doit condenser 2 491 utilisateurs distincts sur un demi-million de lignes correspondantes. Cela ne deviendra pas ultra-rapide, quoi que vous fassiez, mais cela peut être considérablement plus rapide.
Si les intervalles de temps dans vos requêtes sont toujours les mêmes, un MATERIALIIZED VIEW
pliage user_id
par (project_id, <fixed time intervall>)
irait très loin. Aucune chance là-bas avec des intervalles de temps variables, cependant. Peut-être pourriez-vous au moins plier les utilisateurs par heure ou une autre unité de temps minimale, et cela permettrait d'acheter suffisamment de performances pour justifier les frais généraux considérables.
Nitpick:
Très probablement, les prédicats sur "time"
devraient vraiment être:
AND "time" >= '2015-01-11 8:00:00'
AND "time" < '2015-02-10 8:00:00';
À part:
Ne pas utiliser time
comme identifiant. C'est un mot réservé dans SQL standard et un type de base dans Postgres.
Voici mon test sur le cas de Sam et la réponse d'Erwin
Erwin a déclaré: "Vous ne voulez probablement pas entendre cela, mais la meilleure option pour accélérer SELECT DISTINCT est d'éviter d'abord DISTINCT. Dans de nombreux cas (pas tous!), Cela peut être évité avec une meilleure conception de base de données ou de meilleures requêtes. ". Je pense qu'il a raison, nous devons éviter d'utiliser "distinct, grouper, classer par" (le cas échéant).
J'ai rencontré une situation comme le cas de Sam et je pense que Sam peut utiliser la partition sur la table des événements par mois. Cela réduira la taille de vos données lorsque vous interrogerez, mais vous aurez besoin d'une fonction (pl / pgsql) pour exécuter au lieu de la requête ci-dessus. La fonction trouvera les partitions appropriées (en fonction des conditions) pour exécuter la requête.
la source