从 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
、 kr
、kro
、rok
和ok
可能出现非常频繁,这也会导致索引性能不佳。
【讨论】:
以上是关于从 MySQL 迁移到 PostgreSQL 后类似查询的 SQL 性能问题的主要内容,如果未能解决你的问题,请参考以下文章
从 MySQL 迁移到 PostgreSQL 后类似查询的 SQL 性能问题
从 mysql 迁移到 postgresql 时,Laravel 雄辩的 ORM 不起作用
从 MSSQL 迁移到 postgresql 或 mysql [关闭]
AskTUG 论坛迁移实战:Discourse 从 PostgreSQL 到 MySQL 到 TiDB | 极客分享第 36 期