Lar*_*ars 12 postgresql performance postgresql-9.6 query-performance
简单的数据库结构(用于在线论坛):
CREATE TABLE users (
id integer NOT NULL PRIMARY KEY,
username text
);
CREATE INDEX ON users (username);
CREATE TABLE posts (
id integer NOT NULL PRIMARY KEY,
thread_id integer NOT NULL REFERENCES threads (id),
user_id integer NOT NULL REFERENCES users (id),
date timestamp without time zone NOT NULL,
content text
);
CREATE INDEX ON posts (thread_id);
CREATE INDEX ON posts (user_id);
Run Code Online (Sandbox Code Playgroud)
表中大约有 8users
万个条目和 260 万个条目posts
。这个通过帖子获得前 100 位用户的简单查询需要2.4 秒:
EXPLAIN ANALYZE SELECT u.id, u.username, COUNT(p.id) AS PostCount FROM users u
INNER JOIN posts p on p.user_id = u.id
WHERE u.username IS NOT NULL
GROUP BY u.id
ORDER BY PostCount DESC LIMIT 100;
Run Code Online (Sandbox Code Playgroud)
CREATE TABLE users (
id integer NOT NULL PRIMARY KEY,
username text
);
CREATE INDEX ON users (username);
CREATE TABLE posts (
id integer NOT NULL PRIMARY KEY,
thread_id integer NOT NULL REFERENCES threads (id),
user_id integer NOT NULL REFERENCES users (id),
date timestamp without time zone NOT NULL,
content text
);
CREATE INDEX ON posts (thread_id);
CREATE INDEX ON posts (user_id);
Run Code Online (Sandbox Code Playgroud)
随着set enable_seqscan = false
更糟糕:
EXPLAIN ANALYZE SELECT u.id, u.username, COUNT(p.id) AS PostCount FROM users u
INNER JOIN posts p on p.user_id = u.id
WHERE u.username IS NOT NULL
GROUP BY u.id
ORDER BY PostCount DESC LIMIT 100;
Run Code Online (Sandbox Code Playgroud)
username
Postgres 中缺少Group by ,因为它不是必需的(SQL Server 说username
如果我想选择用户名,我必须分组)。分组与username
在 Postgres 上的执行时间增加了一点点毫秒或什么都不做。
对于科学,我已将 Microsoft SQL Server 安装到同一台服务器(运行 archlinux、8 核 xeon、24 gb ram、ssd)并从 Postgres 迁移所有数据 -相同的表结构、相同的索引、相同的数据。获取前 100 张海报的相同查询在0.3 秒内运行:
SELECT TOP 100 u.id, u.username, COUNT(p.id) AS PostCount FROM dbo.users u
INNER JOIN dbo.posts p on p.user_id = u.id
WHERE u.username IS NOT NULL
GROUP BY u.id, u.username
ORDER BY PostCount DESC
Run Code Online (Sandbox Code Playgroud)
从相同的数据产生相同的结果,但速度提高 8 倍。它是 Linux 上 MS SQL 的测试版,我想在它的“家庭”操作系统 - Windows Server 上运行 - 它可能会更快。
我的 PostgreSQL 查询是完全错误的,还是 PostgreSQL 很慢?
版本几乎是最新的(9.6.1,目前最新的是9.6.2,ArchLinux只是包过时,更新很慢)。配置:
max_connections = 75
shared_buffers = 3584MB
effective_cache_size = 10752MB
work_mem = 24466kB
maintenance_work_mem = 896MB
dynamic_shared_memory_type = posix
min_wal_size = 1GB
max_wal_size = 2GB
checkpoint_completion_target = 0.9
wal_buffers = 16MB
default_statistics_target = 100
Run Code Online (Sandbox Code Playgroud)
EXPLAIN ANALYZE
输出:https : //pastebin.com/HxucRgnk
尝试了所有索引,甚至使用了 GIN 和 GIST,PostgreSQL 的最快方法(谷歌搜索确认了很多行)是使用顺序扫描。
MS SQL Server 14.0.405.200-1,默认配置。
我在 API 中使用它(使用没有分析的简单选择),并用 chrome 调用这个 API 端点,它说它需要 2500 毫秒 +-,增加 50 毫秒的 HTTP 和 Web 服务器开销(API 和 SQL 在同一台服务器上运行) - 一样的。我不在乎这里或那里的 100 毫秒,我关心的是整整两秒。
explain analyze SELECT user_id, count(9) FROM posts group by user_id;
需要 700 毫秒。posts
表的大小是 2154 MB。
小智 8
这可能有效,也可能无效 - 我的直觉是它在组和过滤器之前加入您的表。我建议尝试以下操作:在尝试加入之前使用 CTE 过滤和分组:
with
__posts as(
select
user_id,
count(1) as num_posts
from
posts
group by
user_id
order by
num_posts desc
limit 100
)
select
users.username,
__posts.num_posts
from
users
inner join __posts on(
__posts.user_id = users.id
)
order by
num_posts desc
Run Code Online (Sandbox Code Playgroud)
查询规划器有时只需要一点指导。这个解决方案在这里很有效,但在某些情况下 CTE 可能很糟糕。CTE 专门存储在内存中。因此,大数据返回可能会超过 Postgres 分配的内存并开始交换(MS 中的分页)。CTE 也无法编入索引,因此在查询 CTE 时,足够大的查询仍可能导致显着减慢。
您可以真正接受的最佳建议是尝试多种方法并检查您的查询计划。
小智 1
另一个好的查询变体是:
SELECT p.user_id, p.cnt AS PostCount
FROM users u
INNER JOIN (
select user_id, count(id) as cnt from posts group by user_id
) as p on p.user_id = u.id
WHERE u.username IS NOT NULL
ORDER BY PostCount DESC LIMIT 100;
Run Code Online (Sandbox Code Playgroud)
它不会利用 CTE 并给出正确的答案(理论上 CTE 示例可能会生成少于 100 行,因为它首先限制然后与用户连接)。
我想,MSSQL 能够在其查询优化器中执行此类转换,而 PostgreSQL 无法在连接下下推聚合。或者 MSSQL 只是有更快的哈希连接实现。
归档时间: |
|
查看次数: |
8013 次 |
最近记录: |