Sql 函数用于在大型表上执行日期和时间之间的慢速查询

Sql 函数用于在大型表上执行日期和时间之间的慢速查询,sql,postgresql,database-performance,database-indexes,Sql,Postgresql,Database Performance,Database Indexes,我使用的是PostgreSQL,我使用以下查询: SELECT r.name,count(r.name) from rooms r where to_date(dateinput,'YYYYMMDD') between r.start_date and r.end_date or to_char(r.end_time,'HH24:MI:SS')<> '00:00:00') and (r.name in ('nameA','nameB')) group by r.name 执行时间减

我使用的是PostgreSQL,我使用以下查询:

SELECT r.name,count(r.name)
from rooms r
where to_date(dateinput,'YYYYMMDD') between r.start_date and r.end_date
or to_char(r.end_time,'HH24:MI:SS')<> '00:00:00')
and (r.name in ('nameA','nameB'))
group by r.name

执行时间减少到786毫秒。我认为,日期和时间之间的间隔会使索引无法运行。我找不到任何文档或示例来解释为什么在使用to_date和between时不能使用索引。我不知道为什么修改查询会将时间减少到786毫秒。有人能帮我吗?

索引不能用于任何一个查询,执行时间的差异可能是因为第一个查询必须从磁盘读取更多数据,而在第二个查询期间,这些数据已经缓存在RAM共享缓冲区中

奇怪的OR条件使得这个查询很难有效,而且要结束时间,'HH24:MI:SS'是不可能索引的,我不理解它的含义

您必须在不使用联合的情况下重写查询,或者使用联合,并在结束时以不同的方式表示条件,然后您可以使用索引来加快查询速度

我会像这样重写查询:

SELECT r.name, count(r.name)
FROM (SELECT r.name
      FROM rooms r
      WHERE to_date(dateinput,'YYYYMMDD') <@ daterange(r.start_date, r.end_date, '[]')
        AND r.name IN ('nameA','nameB')
      UNION
      SELECT r.name
      FROM rooms r
      WHERE r.end_time <> TIME '00:00:00'
        AND r.name IN ('nameA','nameB')
     ) AS r
GROUP BY r.name;
这些索引可以帮助:

CREATE INDEX ON rooms USING gist (daterange(r.start_date, r.end_date, '[]')) WHERE r.name IN ('nameA','nameB');

CREATE INDEX ON rooms (name) WHERE r.end_time <> TIME '00:00:00' AND r.name IN ('nameA','nameB');

索引不能用于这两个查询,时间差可能是偶然的,或者是因为第二个查询在缓存中找到的表比第一个查询多。您显示的两个查询在语法上都不正确,将不会运行。请显示正确的查询@我只是编辑查询。请help@LaurenzAlbe因为第二个查询在缓存中找到的表比第一个多。=>我不明白。你能解释一下吗?为什么你知道这个名字a和nameB会改变还是总是一样?@LaurenzAlbe它修复了nameA和nameB。不要改变。谢谢你的回答。我的结束时间类型:不带时区的时间。我使用“charr.end\u time,'HH24:MI:SS”,因为我想将其转换为char,并将其与开始时间进行比较。所以,您能解释一下为什么当我删除函数以确定查询日期时,我的查询会减少很多时间吗。任何重写问题的建议我都在答案中添加了建议。谢谢你的建议。这对我帮助很大。我有个问题?我可以使用btree在房间上创建索引吗?为什么我需要在这里使用gist,因为索引是在范围类型上的,而范围类型不支持B树索引。
CREATE INDEX ON rooms USING gist (daterange(r.start_date, r.end_date, '[]')) WHERE r.name IN ('nameA','nameB');

CREATE INDEX ON rooms (name) WHERE r.end_time <> TIME '00:00:00' AND r.name IN ('nameA','nameB');