如何让 date_part 查询命中索引?

2023-12-02

我还没有能够让这个查询命中索引而不是执行完整扫描 - 我有另一个查询,它对几乎相同的表使用 date_part('day', datelocal) (该表的数据稍微少一些,但是相同的结构),并且将命中我在 datelocal 列上创建的索引(这是一个没有时区的时间戳)。查询(此查询对表执行并行 seq 扫描并执行内存快速排序):

SELECT
    date_part('hour', datelocal) AS hour,
    SUM(CASE WHEN gender LIKE 'male' THEN views ELSE 0 END) AS male,
    SUM(CASE WHEN gender LIKE 'female' THEN views ELSE 0 END) AS female
FROM reportimpression
WHERE datelocal >= '2-1-2019' AND datelocal < '2-28-2019'
GROUP BY date_part('hour', datelocal)
ORDER BY date_part('hour', datelocal)

这是确实命中我的日期本地索引的另一项:

SELECT
    date_part('day', datelocal) AS day,
    SUM(CASE WHEN gender LIKE 'male' THEN views ELSE 0 END) AS male,
    SUM(CASE WHEN gender LIKE 'female' THEN views ELSE 0 END) AS female
FROM reportimpressionday
WHERE datelocal >= '2-1-2019' AND datelocal < '2-28-2019'
GROUP BY date_trunc('day', datelocal), date_part('day', datelocal)
ORDER BY date_trunc('day', datelocal)

为这件事让我头疼!关于如何加快第一个或至少使其达到索引的任何想法?我尝试在 datelocal 字段上创建索引,在 datelocal、性别和视图上创建复合索引,以及在 date_part('hour', datelocal) 上创建表达式索引,但这些都不起作用。

Schemas:

-- Table Definition ----------------------------------------------

CREATE TABLE reportimpression (
    datelocal timestamp without time zone,
    devicename text,
    network text,
    sitecode text,
    advertisername text,
    mediafilename text,
    gender text,
    agegroup text,
    views integer,
    impressions integer,
    dwelltime numeric
);

-- Indices -------------------------------------------------------

CREATE INDEX reportimpression_datelocal_index ON reportimpression(datelocal timestamp_ops);
CREATE INDEX reportimpression_viewership_index ON reportimpression(datelocal timestamp_ops,views int4_ops,impressions int4_ops,gender text_ops,agegroup text_ops);
CREATE INDEX reportimpression_test_index ON reportimpression(datelocal timestamp_ops,(date_part('hour'::text, datelocal)) float8_ops);
-- Table Definition ----------------------------------------------

CREATE TABLE reportimpressionday (
    datelocal timestamp without time zone,
    devicename text,
    network text,
    sitecode text,
    advertisername text,
    mediafilename text,
    gender text,
    agegroup text,
    views integer,
    impressions integer,
    dwelltime numeric
);

-- Indices -------------------------------------------------------

CREATE INDEX reportimpressionday_datelocal_index ON reportimpressionday(datelocal timestamp_ops);
CREATE INDEX reportimpressionday_detail_index ON reportimpressionday(datelocal timestamp_ops,views int4_ops,impressions int4_ops,gender text_ops,agegroup text_ops);

解释(分析、缓冲)输出:

Finalize GroupAggregate  (cost=999842.42..999859.67 rows=3137 width=24) (actual time=43754.700..43754.714 rows=24 loops=1)
  Group Key: (date_part('hour'::text, datelocal))
  Buffers: shared hit=123912 read=823290
  I/O Timings: read=81228.280
  ->  Sort  (cost=999842.42..999843.99 rows=3137 width=24) (actual time=43754.695..43754.698 rows=48 loops=1)
        Sort Key: (date_part('hour'::text, datelocal))
        Sort Method: quicksort  Memory: 28kB
        Buffers: shared hit=123912 read=823290
        I/O Timings: read=81228.280
        ->  Gather  (cost=999481.30..999805.98 rows=3137 width=24) (actual time=43754.520..43777.558 rows=48 loops=1)
              Workers Planned: 1
              Workers Launched: 1
              Buffers: shared hit=123912 read=823290
              I/O Timings: read=81228.280
              ->  Partial HashAggregate  (cost=998481.30..998492.28 rows=3137 width=24) (actual time=43751.649..43751.672 rows=24 loops=2)
                    Group Key: date_part('hour'::text, datelocal)
                    Buffers: shared hit=123912 read=823290
                    I/O Timings: read=81228.280
                    ->  Parallel Seq Scan on reportimpression  (cost=0.00..991555.98 rows=2770129 width=17) (actual time=13.097..42974.126 rows=2338145 loops=2)
                          Filter: ((datelocal >= '2019-02-01 00:00:00'::timestamp without time zone) AND (datelocal < '2019-02-28 00:00:00'::timestamp without time zone))
                          Rows Removed by Filter: 6792750
                          Buffers: shared hit=123912 read=823290
                          I/O Timings: read=81228.280
Planning time: 0.185 ms
Execution time: 43777.701 ms

好吧,您的两个查询都在不同的表上(reportimpression vs. reportimpressionday),所以两个查询的比较实际上不是比较。你是否ANALYZE两个都?各种列统计数据也可能发挥作用。索引或表膨胀可能不同。所有行中的大部分是否符合 2019 年 2 月的条件? ETC。

盲目一试,比较两个表的百分比:

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;

是为了reportimpression大?那么它可能会超出索引预计可以帮助的数量。

一般来说,你的索引reportimpression_datelocal_indexon (datelocal) 看起来不错,并且reportimpression_viewership_index如果 autovacuum 击败了表上的写入负载,甚至允许仅索引扫描。 (尽管impressions & agegroup对于这个来说只是死运费,如果没有的话它会工作得更好)。

Answer

You got 26.6 percent, and day is 26.4 percent对于我的查询。对于如此大的百分比,索引通常没有用处at all。顺序扫描通常是最快的方法。仅进行仅索引扫描may如果基础表更大的话仍然有意义。 (或者你有severe表膨胀,索引膨胀更少,这使得索引再次变得更有吸引力。)

您的第一个查询可能刚刚跨越临界点。尝试缩小时间范围,直到看到仅索引扫描。您不会看到超过大约 5% 的所有行符合资格的(位图)索引扫描(取决于许多因素)。

Queries

尽管如此,请考虑这些修改后的查询:

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;

主要观点

  • 使用本地化时日期格式 like '2-1-2019', 经过to_timestamp()具有明确的格式说明符。否则,这取决于区域设置,并且当从具有不同设置的会话调用时可能会(静默)中断。而是使用 ISO 日期/时间格式(如图所示),该格式不依赖于区域设置。

  • 看起来您想包括整整一个月二月。但您的查询错过了上限。例如,二月可能有 29 天。一个datelocal < '2-28-2019'也不包括 2 月 28 日的所有时间。使用datelocal < '2019-03-01'反而。

  • 比较便宜的是按相同表达式进行分组和排序正如你在SELECT如果可以的话列出来。所以使用date_trunc()那里也有。没有必要时不要使用不同的表达方式。如果你need结果中的日期部分,将其应用于分组表达式,例如:

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

    代码噪音更大,但速度更快(并且可能也更容易针对查询规划器进行优化)。

  • Use the 总计的FILTER clause在 Postgres 9.4 或更高版本中。它更干净,速度更快一些。看:

    • 如何简化这个游戏统计查询?
    • 对于绝对性能,SUM 更快还是 COUNT 更快?
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何让 date_part 查询命中索引? 的相关文章

  • 在 Postgres 中存储加密数据 [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我需要在 Postgres 中以加密形式存储某些数据 显然 我需要对其进行加密 存储 并且能够读取和解密 做这个的最好方式是什么 The bes
  • Postgres JSONB:数组数组的 where 子句

    postgres 中有 v 9 5 如果有的话 create table json test id varchar NOT NULL data jsonb NOT NULL PRIMARY KEY id 其中 data 是 json 并且包
  • 为 PostgreSQL 查询选择正确的索引

    简化表 CREATE TABLE products product no integer PRIMARY KEY sales integer status varchar 16 category varchar 16 CREATE INDE
  • TimescaleDB 查询选择列值较上一行发生更改的行

    最近刚刚开始使用 TimescaleDB 和 Postgres 来处理大多数数据请求 然而 我遇到了一个问题 即我对时间序列数据的请求效率极低 它是一个可以是任意时间长度 具有特定整数值的数据系列 大多数时候 除非出现异常 否则该值将是相同
  • 格式化多维数组 Python

    如何编写代码来更改多维数组中每个单独数组的值a出现负值后立即归零 所以里面的第二个数组a有负值 12 34 5 6 88 10 30 75 10 会将其所有值及其后的值转为零 将数组变成 12 34 5 6 88 0 0 0 我怎样才能获得
  • 将DataTable批量插入postgreSQL表中

    在 SQL 中 我们执行类似的操作来批量插入数据表 SqlBulkCopy copy new SqlBulkCopy sqlCon copy DestinationTableName strDestinationTable copy Wri
  • PostgreSQL函数中sql语言和plpgsql语言的区别

    我很新数据库开发所以我对下面的例子有一些疑问 函数 f1 语言 SQL create or replace function f1 istr varchar returns text as select hello varchar istr
  • Rails 的多个数据库不适用于远程数据库

    我有一个远程只读 postgres 数据库 它是通过 docker 实例维护的卡尔达诺数据库同步 https github com input output hk cardano db sync 我设法将开发数据库连接到它 它工作正常 但由
  • 切片 Dataframe 时出现 KeyError

    我的代码如下所示 d pd read csv Collector Output csv df pd DataFrame data d dfa df copy dfa dfa rename columns OBJECTID Object ID
  • 使用data.table进行聚合

    经过 SO 用户的多次建议后 我终于尝试将我的代码转换为使用data table library data table DT lt data table plate paste0 plate rep 1 2 each 5 id rep c
  • Mac 上用户“postgres”的密码身份验证失败

    我在创建新的 psql 用户时遇到问题 因为我无法以 postgres 身份登录 psql 我已尝试过 1 sudo u postgres psql 2 sudo u postgres createuser img site P s e 他
  • 如何修复“缺少表的 FROM 子句条目”错误

    我正在尝试根据游戏 ID 获取平台名称 我有如下三个表 我正在尝试加入它们以获得所需的结果 Games Id 1 2 3 4 Game Platforms Id game id platform id 1 1 1 2 1 2 3 3 3
  • 获取 Pandas 数据框中选定值的行和列标签

    我想获取与数据框中某些条件匹配的值的行和列标签 为了保持它的趣味性 我需要它与分层 多 索引一起使用 例如 df pd DataFrame np arange 16 reshape 4 4 columns pd MultiIndex fro
  • 聚合函数在数据框中创建不需要的向量

    我在函数中创建数据帧时遇到了一个奇怪的问题 但是 在 data frame 之外使用相同的方法效果很好 这是基本函数 我用它来计算数据集的平均值 标准差和标准误差 aggregateX lt function formula dataset
  • 使用 psycopg2 转义 Postgres 的 SQL“LIKE”值

    psycopg2 是否有转义 a 值的函数LIKEPostgres 的操作数 例如 我可能想匹配以字符串 20 of all 开头的字符串 所以我想写这样的内容 sql WHERE LIKE myvalue s cursor fetchal
  • 如何使用 SQLite R-Trees 将简单空间索引移植到 Postgres?

    我通过遵循 SQLite R Tree 实现了一个基于边界框的简单空间索引模式tutorial https www sqlite org rtree html 这给了我以下架构 CREATE VIRTUAL TABLE events reg
  • 为什么要为字符变化类型指定长度

    参考 Postgres 文档字符类型 http www postgresql org docs current static datatype character html 我不清楚指定字符变化 varchar 类型的长度 假设 字符串的长
  • 如何在postgresql中编写有关最大行数的约束?

    我认为这是一个很常见的问题 我有一张桌子user id INT 和一张桌子photo id BIGINT owner INT 所有者是一个参考user id 我想向表照片添加一个约束 以防止每个用户将超过 10 张照片输入数据库 写这个的最
  • PostgreSQL WHERE 计数条件

    我在 PostgreSQL 中有以下查询 SELECT COUNT a log id AS overall count FROM Log as a License as b WHERE a license id 7 AND a licens
  • 索引在 NOT IN 或 <> 子句中起作用吗?

    我读过 至少 Oracle 数据库中的普通索引基本上是 B 树结构 因此存储处理适当根节点的记录 小于 根的记录被迭代地存储在树的左侧部分 而 大于 根的记录被存储在右侧部分 正是这种存储方法有助于通过树遍历实现更快的扫描 因为深度和广度都

随机推荐