我已经阅读了相同架构/查询的 MySQL 和 PostgreSQL 之间的性能差异。以下是对文章的简要复述:
PostgreSQL 表是堆表(意味着没有聚集索引)......(Postgres)表的主键查找需要点击索引,查找文件中的位置,然后点击堆表并拉出记录。这意味着随机磁盘 I/O 的数量... InnoDB 使用不同的方法。使用 InnoDB,表是一个 b 树索引(聚集,物理排序)...... PK 查找所需的随机磁盘 I/O 更少......同时,索引扫描需要遍历两个索引而不是一个(index -> PK index -> table row ),这意味着使用主键以外的任何索引最终都会变慢,而顺序扫描仍然更慢。
哪种查询使用 Postgres 比使用 MySQL InnoDB 快得多?
我理解为什么 PK 查找对于 MySQL 来说要好得多。我不明白:
PS Internet 说 Postgres 更适合复杂查询和子查询,但我仍然不明白为什么它更好?
mysql rdbms postgresql performance query-performance postgresql-performance
我们在每晚凌晨 2 点的负载中有一个更新,它有两次将 CPU 固定在 100% 并且在几个小时后从未完成。我强烈怀疑这是因为统计数据不准确导致连接中出现嵌套循环。我无法在具有相同硬件规格和 postgres 配置的较低环境中重现它。
我需要证明嵌套循环正在发生,然后才能放入 RFC 来解决问题(例如调整分析和自动真空设置)。我已经设置了 auto_explain 但这似乎只捕获了实际完成的查询的计划。如何为未完成的查询记录计划?
在 SQL Server 中,我可以通过使用 @get_plans=1 运行 sp_whoisactive 来做到这一点。我正在 Postgres 中寻找类似的东西。到目前为止,我唯一的想法是使用 cron 运行 EXPLAINs,但这似乎非常复杂。
我们有以下数据库结构
CREATE TABLE objects (
id int PRIMARY KEY,
name text,
address text
);
CREATE TABLE tasks (
id int PRIMARY KEY,
object_id int NOT NULL,
actor_id int NOT NULL,
description text
);
CREATE TABLE actors (
id int PRIMARY KEY,
name text
);
Run Code Online (Sandbox Code Playgroud)
用户输入以空格分隔的单词列表(基本上是搜索词),我们必须搜索满足以下条件的任务:如果每个搜索词在任务描述的串联中至少出现一次,则该任务是“匹配”,其关联对象的名称和地址以及关联参与者的名称。
现在,如果我们不关心性能,我们可以这样做(给定查询“foo bar”):
SELECT t.id, t.description
FROM tasks AS t
INNER JOIN actors AS a ON t.actor_id = a.id
INNER JOIN objects AS o ON t.object_id = o.id
WHERE to_tsvector(concat_ws(' ', t.description, o.name, o.address, a.name)) @@ …Run Code Online (Sandbox Code Playgroud) postgresql performance full-text-search postgresql-performance
我们想将我们的数据库从虚拟主机提供商 (postgres 9.0) 移动到我们的本地网络服务器(尝试了 postgres 10 和最新的 11)我们的机器是 windows 服务器,具有 16gb ram 的快速 XEON 机器,仅用于数据库。
但即使在提高 default_statistics_targer = 4000 并分析统计数据之后,我们也无法运行许多以前运行非常快的视图。似乎虚拟主机提供商的服务器经过了微调,我们的执行计划可能出于某种原因很奇怪。
我们的 Postgres 是库存安装配置。
简化的示例查询如下(最大的表是“dale 表,它有几百万条记录大(它是带有外键的绑定表)其他表要小得多,一万条记录(系统是真空分析的,它是全新安装的)
EXPLAIN ANALYZE
SELECT REKLAMACNY_LIST.ID REKLAMACNY_LIST_ID
FROM REKLAMACNY_LIST
WHERE REKLAMACNY_LIST.VALIDTO IS NULL
AND
( SELECT NOT tr.typ_odstupenia::boolean
AND sr.konecny_stav::boolean
FROM dale d1
CROSS JOIN typ_reklamacie tr
CROSS JOIN dale d2
CROSS JOIN stav_reklamacie sr
WHERE TRUE
AND d1.fk7 = reklamacny_list.id
AND d2.fk7 = reklamacny_list.id
AND d1.fk1 = tr.id
AND d2.fk3 = sr.id
AND sr.validto IS NULL …Run Code Online (Sandbox Code Playgroud) 目前尚不清楚当列设置为 时 Postgres 采取的策略NULL:
UPDATE tbl SET
col1 = NULL,
col2 = NULL
WHERE created < current_date - INTERVAL '1 year';
Run Code Online (Sandbox Code Playgroud)
文档https://www.postgresql.org/docs/current/mvcc.html有点冗长和技术性,所以我无法可靠地推断:
是否就地执行设置为 NULL 或复制受影响的行/页?
看起来任何 UPDATE 都应该为 MVCC 语义创建新行,但如果设置为 NULL 是一种特殊情况怎么办?
为了遵守 GDPR,我认为要清空所有个人历史数据,并尝试理解大规模定期数据的含义UPDATE SET x = NULL。我应该考虑VACUUM之后吗?
我有一个分区表...
CREATE TABLE erco.rtprices
(
scedtime timestamp with time zone NOT NULL,
node_id integer NOT NULL,
lmp numeric(12,6),
CONSTRAINT rtprices_pkey PRIMARY KEY (scedtime, node_id)
) PARTITION BY LIST (node_id);
Run Code Online (Sandbox Code Playgroud)
每个都有node_id自己的分区。
如果我进行直接查询(第一个版本),例如:
explain select scedtime, lmp
from erco.rtprices
where node_id = 11111
Run Code Online (Sandbox Code Playgroud)
然后该计划仅对rtprices_11111分区进行顺序扫描。 这就是我要的。
但是,如果我执行(第二个版本)查询,例如
explain select scedtime, lmp
from erco.rtprices
inner join erco.nodes using (node_id)
where nodename = 'somename'
Run Code Online (Sandbox Code Playgroud)
那么该计划包括对每个分区进行顺序扫描,即使此查询与第一个查询一样有限制。
我尝试了上述查询的另一种形式(第三个版本)。
explain select scedtime, lmp
from erco.rtprices
where node_id = (select node_id from erco.nodes where nodename='somename') …Run Code Online (Sandbox Code Playgroud) postgresql execution-plan partitioning postgresql-performance postgresql-13
在我的应用程序服务器中,我想使用LIMIT和对数据集进行分页OFFSET,并另外将数据集的总数返回给用户。
而不是对数据库进行两次远程调用:
select count(1) as total_count from foo;
select c1 from foo;
Run Code Online (Sandbox Code Playgroud)
我认为在单个数据库调用中完成此操作会更明智:
select c1, count(1) over (partition by null) from foo;
Run Code Online (Sandbox Code Playgroud)
但是,与不使用窗口函数相比,添加此窗口函数会导致执行时间长一个数量级。
我觉得这很令人惊讶,因为类似的时间select count(1) from foo只需要两倍的时间select c1 from foo。然而,将其转换为窗口函数会导致性能下降。
此外,使用以下使用子查询的替代方案非常快:
select c1, (select count(1) from foo) as total_count from foo;
Run Code Online (Sandbox Code Playgroud)
我本来期望 postgresql 能够优化partition by null
我在 Oracle 中尝试过这一点,发现了类似的性能损失。
如何解释为什么这里会出现性能损失?对于核心 postgresql 开发人员来说,进行更改以优化这一点是否相对容易,甚至值得,例如通过将 PARTITION BY NULL 的窗口函数转换为子查询?
设置:
drop table foo;
create table foo (c1 int);
insert into foo
select i from …Run Code Online (Sandbox Code Playgroud) postgresql count window-functions postgresql-performance postgresql-13
我使用 Postgres 13 并使用以下 DDL 定义了一个表:
CREATE TABLE item_codes (
code bytea NOT NULL,
item_id bytea NOT NULL,
time TIMESTAMP WITH TIME ZONE NOT NULL,
PRIMARY KEY (item_id, code)
);
CREATE INDEX ON item_codes (code, time, item_id);
Run Code Online (Sandbox Code Playgroud)
我使用以下查询:
SELECT DISTINCT time, item_id
FROM (
(SELECT time, item_id
FROM item_codes
WHERE code = '\x3965623166306238383033393437613338373162313934383034366139653239'
ORDER BY time, item_id
LIMIT 100)
UNION ALL
(SELECT time, item_id
FROM item_codes
WHERE code = '\x3836653432356638366638636338393364373935343938303233343363373561'
ORDER BY time, item_id
LIMIT 100)
) AS items
ORDER …Run Code Online (Sandbox Code Playgroud) postgresql execution-plan union query-performance postgresql-performance
在 PostgreSQL 数据库表上执行“DELETE”操作时,我遇到了严重的性能问题。删除 15488 条记录的执行时间为 79423.768 毫秒,与“INSERT”或“SELECT”等其他操作相比非常慢。对于为什么会发生这种情况以及优化删除操作的可能方法,我将不胜感激。
背景:我使用 PostgreSQL 引擎版本 12.14 作为应用程序的后端,并且我注意到从一个表中删除记录需要花费出乎意料的长时间。涉及的表定义了索引和约束,数据库大小相对较小,预计会增长到几 GB。然而,对于这个特定的表,这个问题似乎更加明显,而其他表则表现良好。
硬件是 AWS db.t2.micro 实例,具有 1 个 CPU 核心、1 (GiB) 内存和 20 (GiB) 通用 SSD 用于存储。
column_name_loading表架构,我们尝试从中删除的表。
| 列名称 | 数据类型 | 描述 |
|---|---|---|
| ID | 文本 | 首要的关键 |
| 散列 | 文本 | 首要的关键 |
| 日期_从 | 时间戳 | 首要的关键 |
| 日期到 | 时间戳 | |
| 测量位置uuid | 通用唯一标识符 | 主键、外键 |
| 列名 | 文本 | 不为空 |
| 统计类型id | 文本 | |
| 被忽略 | 布尔值 | |
| 笔记 | 文本 | |
| 更新时间 | 时间戳 | |
| 更新者 | 通用唯一标识符 |
可以看到,上表有一个复合主键,涉及4列。有两个表具有对该column_name_loading表的外键引用
第一桌
ALTER TABLE
logger_main_config_column_name_loading
ADD
CONSTRAINT column_name_loading_fkey FOREIGN KEY (
column_name_loading_measurement_location_uuid,
column_name_loading_id,
column_name_loading_hash,
column_name_loading_date_from
) REFERENCES …Run Code Online (Sandbox Code Playgroud) 在我的 API 中,当存在具有该唯一键的行时,用户可能会发送一个尝试创建新行的请求。
目前,我正在捕获唯一键错误并返回一条消息,指出 X 已存在。但是,首先查找该行(在同一连接上)并且仅在该行不存在时才运行 INSERT 语句是否会更高效?
我的直觉告诉我,从 PostgreSQL 读取错误应该会更有效,但我想确保我正在按照惯用的方式做事。
PostgreSQL 版本为 12
我的 API 中的唯一键不是代理 ID 值,它是由外键与文本值组合而成的组合。如果唯一键约束没有失败,数据库确实已经为此行生成了自己的代理 ID 。所以该行的 ID 不是我要检查的内容。正确的行为是不插入行,因为 FK/文本值在表中需要是唯一的。如果请求包含表中已存在的 FK/文本值,则不应插入任何行。
postgresql ×10
performance ×4
count ×1
delete ×1
mysql ×1
partitioning ×1
rdbms ×1
slow-query ×1
union ×1
vacuum ×1