从 MySQL 迁移到 PostgreSQL 后类似查询的 SQL 性能问题

Posted

技术标签:

【中文标题】从 MySQL 迁移到 PostgreSQL 后类似查询的 SQL 性能问题【英文标题】:SQL Performance problem with like query after migration from MySQL to PostgreSQL 【发布时间】:2021-02-22 10:02:22 【问题描述】:

我使用 pgloader 将我的数据库从 mysql 迁移到 PostgreSQL,它在全局范围内效率更高,但在 PostgreSQL 上具有类似条件的查询更慢。

MySQL : ~1ms PostgreSQL : ~110 毫秒

表信息:

105 列 23 个索引 160 万条记录

列信息:

名称字符变化(30)COLLATE pg_catalog."default" NOT NULL, ratemax3v3 整数 NOT NULL DEFAULT 0,

查询是:

SELECT name, realm, region, class, id 
FROM personnages 
WHERE blacklisted = 0 AND name LIKE 'Krok%' AND region = 'eu'
ORDER BY ratemax3v3 DESC LIMIT 5;

解释分析(PostgreSQL)

 Limit  (cost=629.10..629.12 rows=5 width=34) (actual time=111.128..111.130 rows=5 loops=1)
   ->  Sort  (cost=629.10..629.40 rows=117 width=34) (actual time=111.126..111.128 rows=5 loops=1)
         Sort Key: ratemax3v3 DESC
         Sort Method: top-N heapsort  Memory: 25kB
         ->  Bitmap Heap Scan on personnages  (cost=9.63..627.16 rows=117 width=34) (actual time=110.619..111.093 rows=75 loops=1)
               Recheck Cond: ((name)::text ~~ 'Krok%'::text)
               Rows Removed by Index Recheck: 1
               Filter: ((blacklisted = 0) AND ((region)::text = 'eu'::text))
               Rows Removed by Filter: 13
               Heap Blocks: exact=88
               ->  Bitmap Index Scan on trgm_idx_name  (cost=0.00..9.60 rows=158 width=0) (actual time=110.581..110.582 rows=89 loops=1)
                     Index Cond: ((name)::text ~~ 'Krok%'::text)
 Planning Time: 0.268 ms
 Execution Time: 111.174 ms

Pgloader 已在 ratemax3v3 上创建索引,名称如下:

CREATE INDEX idx_24683_ratemax3v3
ON wow.personnages USING btree
(ratemax3v3 ASC NULLS LAST)
TABLESPACE pg_default;

CREATE INDEX idx_24683_name
ON wow.personnages USING btree
(name COLLATE pg_catalog."default" ASC NULLS LAST)
TABLESPACE pg_default;

我在名称上创建了一个新索引:

CREATE INDEX trgm_idx_name ON wow.personnages USING GIST (name gist_trgm_ops);

我现在是 postgresql 的初学者。 你看到我能做些什么了吗?

如果您需要更多信息,请随时问我!

安东尼

【问题讨论】:

105 columns 23 indexes 对比一下,mysql中使用的索引和计划是什么? 【参考方案1】:

要支持这样的 LIKE 查询(左锚定),您需要使用特殊的“运算符类”:

CREATE INDEX ON wow.personnages(name varchar_pattern_ops);

但是对于您给定的查询,多列上的索引可能会更有效:

CREATE INDEX ON wow.personnages(region, blacklisted, name varchar_pattern_ops);

如果例如,甚至可能是过滤索引blacklisted = 0 是一个静态条件,匹配该条件的行相对较少。

CREATE INDEX ON wow.personnages(region, name varchar_pattern_ops)
WHERE blacklisted = 0; 

如果大多数行都有blacklisted = 0,那将无济于事(并且将列添加到索引也无济于事)。在这种情况下,仅使用 (region, name varchar_pattern_ops) 的索引可能更有效。

【讨论】:

【参考方案2】:

如果您的模式在开始时锚定,则以下索引会表现更好:

CREATE INDEX ON personnages (name text_pattern_ops);

此外,在这种情况下,GIN 索引通常比 GiST 索引执行得更好。尝试使用 GIN 索引。

最后,三元组 k krkrorokok 可能出现非常频繁,这也会导致索引性能不佳。

【讨论】:

以上是关于从 MySQL 迁移到 PostgreSQL 后类似查询的 SQL 性能问题的主要内容,如果未能解决你的问题,请参考以下文章

从 MySQL 迁移到 PostgreSQL 后类似查询的 SQL 性能问题

从 mysql 迁移到 postgresql 时,Laravel 雄辩的 ORM 不起作用

从 MSSQL 迁移到 postgresql 或 mysql [关闭]

AskTUG 论坛迁移实战:Discourse 从 PostgreSQL 到 MySQL 到 TiDB | 极客分享第 36 期

两年内从MySQL迁移到PostgreSQL?这家欧洲科技公司是这么做的

在 Linux (Kubuntu) 上从 MySQL 迁移到 PostgreSQL