postgresql - column1 的索引 = x AND column2 <= y ORDER BY column3 DESC

标签 postgresql types indexing query-optimization

我用谷歌搜索了 15 个不同顺序的不同索引(包括 interval_end, ticker, interval_start DESC )和 ASC/DESC ,最终它使用的唯一一个是 idx_onemin_intervalstart一。 <=我相信运算符(operator)是杀死我的原因。

我已经阅读了所有关于索引的 PostgreSQL 手册,但我仍然感到困惑,这不是一个例子。

查询

explain analyze 
SELECT open 
FROM  onemin_interval 
WHERE ticker = 'QQQ' 
  AND interval_end <= 1326810600000 
ORDER BY interval_start DESC 
LIMIT 19960;

表模式

表格public.onemin_interval

   Column            |     Type      | Modifiers
---------------------+---------------+-----------
 interval_start      | numeric(13,0) | 
 interval_end        | numeric(13,0) |
 open                | numeric(10,2) |
 close               | numeric(10,2) |
 high                | numeric(10,2) |
 low                 | numeric(10,2) |
 volume_for_interval | bigint        |
 ticker              | character(10) |
 humantimeopen       | character(23) |
 humantimeclose      | character(23) |
 adlval              | bigint        |

索引

"idx_onemin_intervalend" btree (interval_end)
"idx_onemin_intervalend_intervalstart" btree (interval_end, interval_start)
"idx_onemin_intervalstart" btree (interval_start DESC)
"idx_onemin_ticker" btree (ticker)
"idx_onemin_ticker_intervalend" btree (ticker, interval_end)

查询计划

Limit  (cost=0.00..10295.29 rows=19960 width=20) (actual time=581.856..1731.352 rows=19960 loops=1)
->  Index Scan Backward using idx_onemin_intervalstart on onemin_interval  (cost=0.00..36843.32 rows=71430 width=20) (actual time=581.842..1621.713 rows=19960 loops=1)
     Filter: ((interval_end <= 1326810600000::numeric) AND (ticker = 'QQQ'::bpchar))
Total runtime: 1791.594 ms
(4 rows)

评论后的新内容

出于测试目的,我添加了大量索引,并运行了 ANALYZE onemin_interval .查询与之前几乎相同:

explain analyze
SELECT open
FROM  onemin_interval
WHERE ticker = 'QQQ'
  AND interval_end <= 1327698068642
ORDER BY interval_start DESC
LIMIT 19960;   

查询计划

Limit  (cost=0.00..5849.68 rows=19960 width=16) (actual time=0.088..394.596 rows=19960 loops=1)
  ->  Index Scan using test11 on onemin_interval  (cost=0.00..21748.74 rows=74210 width=16) (actual time=0.079..298.848 rows=19960 loops=1)
     Filter: ((interval_end <= 1327698068642::bigint) AND (ticker = 'QQQ'::text))
Total runtime: 1442.898 ms
(4 rows)

架构

表格public.onemin_interval

   Column           |     Type      | Modifiers
--------------------+---------------+-----------
interval_start      | bigint        |
interval_end        | bigint        |
open                | numeric       |
close               | numeric       |
high                | numeric       |
low                 | numeric       |
volume_for_interval | bigint        |
ticker              | text          |
humantimeopen       | character(23) |
humantimeclose      | character(23) |
adlval              | bigint        |

索引

"idx_onemin_intervalend" btree (interval_end)
"idx_onemin_intervalend_intervalstart" btree (interval_end, interval_start)
"idx_onemin_intervalstart" btree (interval_start)
"idx_onemin_ticker" btree (ticker)
"idx_onemin_ticker_intervalend" btree (ticker, interval_end)
"test1" btree (interval_end DESC)
"test10" btree (ticker, interval_end DESC, interval_start DESC)
"test11" btree (interval_start DESC)
"test12" btree (interval_start DESC, interval_end DESC, ticker)
"test13" btree (interval_start DESC, ticker, interval_end DESC)
"test14" btree (ticker, interval_start DESC, interval_end DESC)
"test15" btree (interval_end DESC, interval_start DESC, ticker)
"test3" btree (interval_end)
"test4" btree (interval_end DESC, ticker)
"test5" btree (interval_end, ticker)
"test6" btree (ticker, interval_end DESC)
"test7" btree (ticker, interval_end)
"test8" btree (interval_end, ticker)
"test9" btree (interval_end DESC, ticker, interval_start DESC)

最佳答案

数据类型、大小和性能

首先,类型character(n)几乎总是一个糟糕的选择。如果您没有充分的理由并且知道自己在做什么,请使用类型 text 反而。 如果您确实需要强制执行最大长度,请使用 CONSTRAINT。 ticker 列的示例:

ALTER TABLE onemin_interval
ADD CONSTRAINT onemin_interval_ticker_len CHECK (length(ticker) < 11);

显然您有像“QQQ”这样的值,因此长度为 10 似乎是任意的。这将减少表格大小(可能会显着减少)并加快 .. 一切。

另外,考虑使用 bigint而不是 numeric(13,0) .无论如何你都不存储小数位,这可能是更好的设计。 numeric(13,0) 需要 13 个字节 (5 + 4x2),bigint 需要 8 个字节,并且对它的操作在各个方面都更快。

最后:bigint 可以吗?列很简单 integer , 也? (如果 -2147483648 到 +2147483647 的范围在表的整个生命周期内足够大。)

核心问题

为什么索引是idx_onemin_ticker_intervalend没用过?
我会尝试几件事:

显式转换

如果您无法将数据类型更改为 text ,通过显式转换为 character(10) 来测试查询:

WHERE ticker = 'QQQ'::character(10)

旧版本的 PostgreSQL 可能无法为 character(10) 使用索引对于三个字符的未填充字符串 ( 'QQQ' )。但是,在我的测试中,索引同时用于 PostgreSQL 8.4 和 9.1。

多列索引中列的顺序

尝试颠倒多列索引中列的顺序。

idx_onemin_ticker_intervalend btree (interval_end DESC, ticker)

Order of the columns in a multi-column index is relevant .尽管在您的情况下,如果一切正常,它应该是不相关的,因为您在两列中都包含了条件。我仍然会测试这个。

计划者统计

查询规划器似乎期望条件 ticker = 'QQQ' AND interval_end <= 1326810600000不是很有选择性——而事实上,它们似乎非常有选择性(结果 4 行)。尝试提高 default_statistics_target对于这样的两列:

ALTER TABLE onemin_ticker ALTER COLUMN interval_end SET STATISTICS 1000;
ALTER TABLE onemin_ticker ALTER COLUMN ticker SET STATISTICS 1000;
ANALYZE onemin_ticker;

甚至更多,最多 10000(您确实有 42 万行)。默认值为 100。这通常只有助于数据分布不均匀,但对于巨大的表,它应该很容易获得返回。

一般性能优化

一般建议performance optimization in the PostgreSQL Wiki始终适用。


最后,请注意这种查询永远不会很快。对 70k 行进行排序需要时间 - 并且引擎必须在 LIMIT 19960 之前对所有 70k 行进行排序。可以应用。

正如我从您的更新中看到的,查询规划器使用索引 test11 (interval_start DESC) - 这表明排序是查询中最昂贵的操作。

当您在排序之前按多个条件进行选择时,我看不出索引如何进一步帮助您进行排序。您的数据不能预先排序预先选择 - 除非如果WHERE子句是稳定的,那么你可以创建一个部分索引,如:

CREATE INDEX onemin_interval_interval_start_part_idx
  ON    onemin_interval (interval_start DESC)
  WHERE ticker = 'QQQ'::character(10) 
  AND   interval_end <= 1326810600000

...导致减轻脂肪执行。但我不认为你有那么幸运? 如果其中一个标准是稳定的,那么这已经很有帮助了,因此您可以在该标准上建立部分索引。

关于postgresql - column1 的索引 = x AND column2 <= y ORDER BY column3 DESC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9041661/

相关文章:

c# - Npgsql.Npgsql异常 : 'No password has been provided

sql - 我应该如何处理 "forget this"功能背后的数据库逻辑?

linux - Linux 上的 PostgreSQL 数据库默认位置

spring - 不支持 DML 操作。无法使用 spring 数据更新 postgresql 数据库中的数据

swift - Swift 中的隐式类型转换

types - Coq 看不出两种类型是一样的

c - 了解 C 中的 double 运算

Magento:索引管理页面仅显示空白

PHP 单词索引,性能和合理的结果

matlab - 索引移动极差