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

Comment faire en sorte que la requête date_part atteigne l'index ?

Eh bien, vos deux requêtes sont sur des tables différentes (reportimpression vs reportimpressionday ), donc la comparaison des deux requêtes n'est vraiment pas une comparaison. Avez-vous ANALYZE tous les deux? Diverses statistiques de colonne peuvent également jouer un rôle. Le gonflement de l'index ou de la table peut être différent. Une plus grande partie de toutes les rangées est-elle éligible pour février 2019 ? Etc.

Un coup dans le noir, comparez les pourcentages des deux tableaux :

SELECT tbl, round(share * 100 / total, 2) As percentage
FROM  (
   SELECT text 'reportimpression' AS tbl
        , count(*)::numeric AS total
        , count(*) FILTER (WHERE datelocal >= '2019-02-01' AND datelocal < '2019-03-01')::numeric AS share
   FROM  reportimpression

   UNION ALL
   SELECT 'reportimpressionday'
        , count(*)
        , count(*) FILTER (WHERE datelocal >= '2019-02-01' AND datelocal < '2019-03-01')
   FROM  reportimpressionday
  ) sub;

Est-ce celui pour reportimpression plus gros? Ensuite, il pourrait simplement dépasser le nombre pour lequel un index est censé aider.

Généralement, votre index reportimpression_datelocal_index le (datelocal) semble bon pour cela, et reportimpression_viewership_index autorise même les analyses d'index uniquement si autovacuum dépasse la charge d'écriture sur la table. (Bien que les impressions &agegroup sont juste des marchandises mortes pour cela et cela fonctionnerait encore mieux sans).

Répondre

Vous avez 26.6 percent, and day is 26.4 percent pour ma requête. Pour un pourcentage aussi élevé, les index ne sont généralement pas utiles du tout . Une analyse séquentielle est généralement le moyen le plus rapide. Seules les analyses d'index uniquement peuvent ont toujours un sens si la table sous-jacente est beaucoup plus grande. (Ou vous avez grave gonflement des tables et des index moins gonflés, ce qui rend les index à nouveau plus attrayants.)

Votre première requête peut être juste à travers le point de basculement. Essayez de réduire la période jusqu'à ce que vous voyiez des analyses d'index uniquement. Vous ne verrez pas d'analyses d'index (bitmap) avec plus d'environ 5 % de toutes les lignes qualifiées (cela dépend de nombreux facteurs).

Requêtes

Quoi qu'il en soit, considérez ces requêtes modifiées :

SELECT date_part('hour', datelocal)                AS hour
     , SUM(views) FILTER (WHERE gender = 'male')   AS male
     , SUM(views) FILTER (WHERE gender = 'female') AS female
FROM   reportimpression
WHERE  datelocal >= '2019-02-01'
AND    datelocal <  '2019-03-01' -- '2019-02-28'  -- ?
GROUP  BY 1
ORDER  BY 1;

SELECT date_trunc('day', datelocal)                AS day
     , SUM(views) FILTER (WHERE gender = 'male')   AS male
     , SUM(views) FILTER (WHERE gender = 'female') AS female
FROM   reportimpressionday
WHERE  datelocal >= '2019-02-01'
AND    datelocal <  '2019-03-01'
GROUP  BY 1
ORDER  BY 1;

Points majeurs

  • Lors de l'utilisation du format de date localisé comme '2-1-2019' , passez par to_timestamp() avec des spécificateurs de format explicites. Sinon, cela dépend des paramètres régionaux et peut se briser (silencieusement) lorsqu'il est appelé à partir d'une session avec des paramètres différents. Utilisez plutôt les formats de date/heure ISO comme démontré qui ne dépendent pas des paramètres régionaux.

  • Il semble que vous souhaitiez inclure le mois entier de février. Mais votre requête manque la limite supérieure. D'une part, février peut avoir 29 jours. Un datelocal < '2-28-2019' exclut également tout le 28 février. Utilisez datelocal < '2019-03-01' à la place.

  • Il est moins cher de regrouper et trier par la même expression comme vous l'avez dans le SELECT liste si vous le pouvez. Utilisez donc date_trunc() ici aussi. N'utilisez pas d'expressions différentes sans nécessité. Si vous avez besoin la partie de date dans le résultat, appliquez-la sur l'expression groupée, comme :

    SELECT date_part('day', date_trunc('day', datelocal)) AS day
    ...
    GROUP  BY date_trunc('day', datelocal)
    ORDER  BY date_trunc('day', datelocal);
    

    Code un peu plus bruyant, mais plus rapide (et peut-être plus facile à optimiser également pour le planificateur de requêtes).

  • Utilisez le agrégat FILTER clause dans Postgres 9.4 ou ultérieur. C'est plus propre et un peu plus rapide. Voir :