标签: postgresql

对数十亿行表的慢查询 // 使用的索引

由于我是一名年轻的开发人员并且不太擅长使用数据库(PostgreSQL 9.3),因此我在项目中遇到了一些问题,我确实需要帮助。

我的项目是关于从设备(最多 1000 个或更多设备)收集数据,其中每个设备每秒发送一个数据块,每小时大约生成 300 万行。

目前我有一张大表,用于存储每个设备的传入数据:

CREATE TABLE data_block(
    id bigserial
    timestamp timestamp
    mac bigint
)
Run Code Online (Sandbox Code Playgroud)

由于数据块可以(或不可以)包含多种类型的数据,因此还有其他表引用该data_block表。

CREATE TABLE dataA(
    data_block_id bigserial
    data

    CONSTRAINT fkey FOREIGN KEY (data_block_id) REFERENCES data_block(id);
);
CREATE TABLE dataB(...);
CREATE TABLE dataC(...);
CREATE INDEX index_dataA_block_id ON dataA (data_block_id DESC);
...
Run Code Online (Sandbox Code Playgroud)

有可能在一个 data_block 中有 3x dataA、1x dataB,但没有 dataC。

数据将保留数周,因此该表中将有大约 50 亿行。目前,我在表中有大约 6 亿行,我的查询需要很长时间。所以我决定在timestampand上做一个索引mac,因为我的 select 语句总是随着时间的推移而查询,而且通常也随着时间+mac。

CREATE INDEX index_ts_mac ON data_block (timestamp DESC, mac);
Run Code Online (Sandbox Code Playgroud)

...但我的查询仍然需要很长时间。比如我查询了一天一台mac的数据:

SELECT * FROM data_block …
Run Code Online (Sandbox Code Playgroud)

postgresql performance postgresql-9.3 query-performance

11
推荐指数
1
解决办法
1万
查看次数

向表中添加可为空列的成本超过 10 分钟

我在表上添加新列时遇到问题。
我尝试运行了几次,但是运行了 10 多分钟后,由于锁定时间,我决定取消查询。

ALTER TABLE mytable ADD mycolumn VARCHAR(50);
Run Code Online (Sandbox Code Playgroud)

有用的信息:

  • PostgreSQL 版本:9.1
  • 行数:~ 250K
  • 列数:38
  • 可空列数:32
  • 约束数量:5(1 PK、3 FK、1 UNIQUE)
  • 索引数:1
  • 操作系统类型:Debian Squeeze 64

我发现了有关 PostgreSQL 管理可空列的方式的有趣信息(通过 HeapTupleHeader)。

我的第一个猜测是,因为这个表已经有 32 个 8 位的可空列MAXALIGN, HeapTupleHeader 是 4 字节长度(未验证,我不知道如何这样做)。

因此,添加新的可为空的列可能需要在每一行上更新 HeapTupleHeader 以添加新的 8-bits MAXALIGN,这可能会导致性能问题。

因此,我尝试更改可空列之一(实际上并不是真正可以为空的),以便将可空列的数量减少到 31,以检查我的猜测是否属实。

ALTER TABLE mytable ALTER myothercolumn SET NOT NULL;
Run Code Online (Sandbox Code Playgroud)

不幸的是,这个改动也需要很长时间,超过5分钟,所以我也中止了。

您知道是什么导致了这种性能成本吗?

postgresql database-design alter-table postgresql-9.1

11
推荐指数
1
解决办法
4025
查看次数

为什么 CTE 对丢失的更新开放?

我不明白 Craig Ringer 在评论时的意思:

如果插入事务回滚,此解决方案可能会丢失更新;没有强制执行 UPDATE 影响任何行的检查。

/sf/answers/609160401/ 上。请提供一个示例事件序列(例如,线程 1 执行 X,线程 2 执行 Y)以演示丢失更新是如何发生的。

postgresql cte concurrency upsert

11
推荐指数
1
解决办法
5124
查看次数

如何确定添加索引的成本/收益?

根据克雷格·林格的说法:

虽然在(或包括)引用端外键列上创建索引通常是个好主意,但这不是必需的。您添加的每个索引都会稍微减慢 DML 操作的速度,因此您需要为每个INSERT,UPDATE或支付性能成本DELETE。如果索引很少使用,它可能不值得拥有。

您如何确定添加索引的收益是否超过其成本?

您是否在添加索引之前/之后分析单元测试并检查整体性能提升?或者,还有更好的方法?

postgresql index optimization

11
推荐指数
1
解决办法
2853
查看次数

如何在 PostgresQL 表中删除未命名的检查约束?

我创建了一个 PostgresQL 表,但我在其中一列上添加了一个未命名的检查约束:

CREATE TABLE FOO
(
id serial primary key,
price_range smallint CHECK (price_range > 0),
url varchar(255)
);
Run Code Online (Sandbox Code Playgroud)

现在我想删除这个约束,但我不知道如何。典型的 ALTER TABLE...DROP CONSTRAINT... 需要一个,constraint_name但我没有。

我知道这里有一个答案但是当我尝试按照那里的答案确定检查约束的名称时:

SELECT *
FROM information_schema.constraint_table_usage
WHERE table_name = 'your_table'
Run Code Online (Sandbox Code Playgroud)

我得到的只是一个约束,它的constraint_name条目是foo pkey指主键约束,而不是我对price列的检查。所以这个答案对我没有帮助,除非我遗漏了什么。

如何在不丢失任何数据的情况下删除此约束?

谢谢!

postgresql

11
推荐指数
1
解决办法
6895
查看次数

如何防止 PostgreSQL 触发器被另一个触发器触发?

我在一张桌子上有 2 个触发器;一种适用于插入:

CREATE TRIGGER "get_user_name"
AFTER INSERT ON "field_data"
FOR EACH ROW EXECUTE PROCEDURE "add_info"();
Run Code Online (Sandbox Code Playgroud)

这会更新表中的一些值。
还有一个用于更新(填充历史表):

CREATE TRIGGER "set_history"
BEFORE UPDATE ON "field_data"
FOR EACH ROW EXECUTE PROCEDURE "gener_history"();
Run Code Online (Sandbox Code Playgroud)

问题是,当我在表中插入新行时,该过程"add_info"()会进行更新并因此触发第二个触发器,该触发器以错误结束:

ERROR:  record "new" has no field "field1"
Run Code Online (Sandbox Code Playgroud)

我怎样才能避免这种情况?

postgresql trigger plpgsql postgresql-9.3

11
推荐指数
2
解决办法
7709
查看次数

相似度函数的最佳索引

所以我有这个包含 620 万条记录的表,我必须对列执行具有相似性的搜索查询。查询可以是:

 SELECT  "lca_test".* FROM "lca_test"
 WHERE (similarity(job_title, 'sales executive') > 0.6)
 AND worksite_city = 'los angeles' 
 ORDER BY salary ASC LIMIT 50 OFFSET 0
Run Code Online (Sandbox Code Playgroud)

可以在 where(year = X, worksite_state = N, status = 'certified',visa_class = Z) 中添加更多条件。

运行其中一些查询可能需要很长时间,超过 30 秒。有时超过一分钟。

EXPLAIN ANALYZE 前面提到的查询给了我这个:

Limit  (cost=0.43..42523.04 rows=50 width=254) (actual time=9070.268..33487.734 rows=2 loops=1)
->  Index Scan using index_lca_test_on_salary on lca_test  (cost=0.43..23922368.16 rows=28129 width=254) (actual time=9070.265..33487.727 rows=2 loops=1)
>>>> Filter: (((worksite_city)::text = 'los angeles'::text) AND (similarity((job_title)::text, 'sales executive'::text) > 0.6::double precision)) …
Run Code Online (Sandbox Code Playgroud)

postgresql index full-text-search pattern-matching postgresql-9.3

11
推荐指数
1
解决办法
8946
查看次数

VACUUM FULL 是否需要 ANALYZE

如果您能深入了解VACUUMPostgreSQL 9.3 中的功能,我将不胜感激。我通读了文档并进行了一些搜索,但找不到明确的答案。

我正在为 9.3 服务器设置每周一次的数据库维护工作。

其中一部分将是一个VACUUM FULL. 这是一个很小的数据库,我有一个不错的周末维护窗口,所以我可以FULL毫无问题地运行它。

ANALYZE在命令中添加选项有什么意义吗?

根据 9.3 文档:

VACUUM FULL 将表的全部内容重写到一个没有额外空间的新磁盘文件中,允许将未使用的空间返回给操作系统。

如果表已完全重新创建,那么我是否需要特别要求ANALYZE发生或在将行写入表的新版本时自动更新统计信息?

postgresql statistics vacuum postgresql-9.3

11
推荐指数
1
解决办法
4915
查看次数

PostgreSQL 三元组 GIST 与 GIN 索引

我有一个 PostgreSQL 9.1 数据库,其中包含 10M+ 行和一些需要相似性和类似%word%搜索的文本字段,所以我决定使用 trigram 索引。

最初,我开始使用 GIN 索引,但现在我想知道我是否应该使用 GIST。

该理论说:

  • GIN 索引查找速度大约是 GiST 的三倍
  • GIN 索引的构建时间大约是 GiST 的三倍
  • GIN 索引的更新速度比 GiST 索引稍慢,但如果禁用快速更新支持,则大约慢 10 倍(有关详细信息,请参阅第 58.4.1 节)
  • GIN 索引比 GiST 索引大两到三倍

我试图同时创建GINGIST索引,并在实践中发现以下内容(在我的数据集上):

  • 对于LIKE '%word%'查询,GIN 的速度与第一次 GIST 大致相同(甚至慢 5-20%)(当查询中的三元组索引尚未缓存时)。
  • 对于LIKE '%word%'查询,如果最近搜索了查询中的三元组,GIN 大约比 GIST 快5倍。无论缓存如何,GIST 始终具有相同的速度。
  • 对于% 'word'(相似性)查询,GIN 大约比 GIST5-8倍,具体取决于索引的缓存性。
  • GIN比 GIST约 10% 。但是,如果UPDATE表中有语句,它似乎增长得更快。除非,当然,我VACUUM FULL经常不够。

所以我看到了理论和实践之间的一些差异:

  1. 速度 …

postgresql full-text-search postgresql-9.1

11
推荐指数
0
解决办法
3546
查看次数

带有类型修饰符的数据类型的惊人结果

在讨论这个问题的递归 CTE 解决方案时:

@ypercube偶然发现了一个令人惊讶的异常,这导致我们调查类型修饰符的处理。我们发现了令人惊讶的行为。

1. 类型转换在某些上下文中保留了类型修饰符

即使被指示不要这样做。最基本的例子:

SELECT 'vc8'::varchar(8)::varchar
Run Code Online (Sandbox Code Playgroud)

人们可能会期望varchar(没有修饰符),至少我会。但结果是varchar(8)(带修饰符)。下面的小提琴中有许多相关的案例。

2. 数组连接在某些情况下失去了类型修饰符

不需要,所以这在相反的一面出错:

SELECT ARRAY['vc8']::varchar(8)[]
     , ARRAY['vc8']::varchar(8)[] || 'vc8'::varchar(8)
Run Code Online (Sandbox Code Playgroud)

第一个表达式varchar(8)[]按预期产生。
但是第二个,在连接另一个之后varchar(8)被淡化到只是varchar[](没有修饰符)。来自array_append(),下面小提琴中的示例的类似行为。

在大多数情况下,所有这些都无关紧要。Postgres 不会丢失数据,并且当分配给列时,该值无论如何都会被强制转换为正确的类型。然而,相反方向的错误最终会导致一个令人惊讶的异常:

3. 递归 CTE 要求数据类型完全匹配

鉴于此简化表:

CREATE TABLE a (
  vc8  varchar(8)  -- with modifier
, vc   varchar     -- without  
);
INSERT INTO a VALUES  ('a',  'a'), ('bb', 'bb');
Run Code Online (Sandbox Code Playgroud)

虽然此 rCTE 对varchar列有效vc,但对 …

postgresql datatypes cte debugging cast

11
推荐指数
1
解决办法
1825
查看次数