我試用了PostgreSQL 11的新功能JIT編譯
首先
2018年10月18日,PostgreSQL 11发布了。
-
- PostgreSQL 11 Released
- https://www.postgresql.org/about/news/1894/
大规模数据库的各种功能得到了加强,比如并行查询和分区等等。今天我要分享的是其中一个我个人特别关注的、并且构建起来比较困难的JIT编译功能的验证内容。
在撰写本文时,我参考了各种信息,并附上了相应的链接。
然而,部分链接是关于PostgreSQL 11测试版的验证信息。
请注意,和正式发布的PostgreSQL 11可能存在不同的结果。
引入JIT编译
即使正常安装了PostgreSQL 11,也不一定可以使用JIT编译。
默认情况下,需要安装未安装的库等。
如果从源代码构建PostgreSQL
如果要从源代码搭建PostgreSQL,需要先安装LLVM。 (CentOS 7等默认安装了LLVM,但版本较旧,需要进行调整)
在编译时,需要明确使用LLVM作为选项。
从源代码构建并引入LLVM的步骤在详细的建立和验证网站上有说明。然而,以下信息是关于PostgreSQL 11测试版的信息。请注意,目前可能存在升级所需LLVM版本的情况。
如果从RPM安装PostgreSQL的话
以前我写过一篇文章(推广)关于使用RPM安装PostgreSQL。
请参考这篇文章获取详细的安装步骤。
适用于初学者和注重细节的用户从RPM安装PostgreSQL。
在线环境下
通过上述文章介绍的从RPM安装PostgreSQL,可以使用JIT支持的构建。但是由于操作系统上的LLVM版本可能无法正确配合,所以需要注意。
有关LLVM版本升级的方法,请参考本网站提供的建设和验证相关内容的链接。
在离线环境下
LLVM可以从EPEL(Linux扩展包)获取。
这次我们将获取5.0或以上的版本。
-
- EPEL/ja
- https://fedoraproject.org/wiki/EPEL/ja
在离线环境下,可以直接从上述的网站获取所需的RPM,并将其安装在目标环境中。
在CentOS 7上,
从https://dl.fedoraproject.org/pub/epel/7/x86_64/Packages/l/
下载”llvm5.0-libs-5.0.1-7.el7.x86_64.rpm”和”llvm5.0-5.0.1-7.el7.x86_64.rpm”。
yum install llvm5.0-libs-5.0.1-7.el7.x86_64.rpm
yum install llvm5.0-5.0.1-7.el7.x86_64.rpm
从以下网站选择适当的操作系统行和版本号,您可以找到所有与PostgreSQL相关的RPM包。然后获取LLVM相关的RPM。
-
- PostgreSQL RPM Chart
- https://yum.postgresql.org/rpmchart.php
在CentOS 7环境中,下载PostgreSQL 11的文件「postgresql11-llvmjit-11.0-1PGDG.rhel7.x86_64.rpm」,链接为https://download.postgresql.org/pub/repos/yum/11/redhat/rhel-7.4-x86_64/。
yum install postgresql11-llvmjit-11.0-1PGDG.rhel7.x86_64.rpm
这样一来,就成为了能够使用JIT编译的环境。
让我们实际尝试使用一下
即使JIT编译可以使用,也并非立即可用。
需要调整相关参数。
关于参数问题,我们有手册和PostgreSQL 11来帮忙!(1)- 参考了参数差异的文章。
除了JIT相关内容外,由于PostgreSQL 11增加/修改了参数的说明,对于PostgreSQL相关人员来说是必看的。
另外,正如(1)中所述,作者ぬこ@横浜先生撰写了许多关于11版本的文章。
我个人在PostgreSQL 11验证中也参考了这些文章,所以强烈推荐(代传)。
JIT相关的参数
以下是使用JIT编译所需的参数集。
其中jit_above_cost、jit_inline_above_cost和jit_optimize_above_cost这三个参数具有较强的关联性。
您可以通过修改这些参数来正确使用JIT编译。
ベータ版ではデフォルトでonでしたが、正式版ではoffがデフォルトです。jit_above_cost100000JITコンパイルが使用されるかを決めるコストの閾値です。
クエリの推定コストが本値を超えると使用されます。
値が-1の場合、無効化されます。jit_inline_above_cost500000JITコンパイル使用後に、インライン展開するかを決める閾値です。
JITコンパイルのオーバヘッドは増加しますが、クエリ実行時間は減ります。
クエリの推定コストが本値を超えると使用されます。
値が-1の場合、無効化されます。jit_optimize_above_cost500000インライン展開後、高価な最適化をするか決める閾値です。
JITコンパイルのオーバヘッドは増加しますが、クエリ実行時間は減ります。
クエリの推定コストが本値を超えると使用されます。
値が-1の場合、無効化されます。jit_providerllvmjit使用するJITプロパイダを決定します。
現在はLLVMのみ対応しているため変更の必要はありません。
除了这个之外,还有一些供开发者使用的参数,但我认为在正常运营时不需要特别关注。
尝试更改参数并使用JIT编译
只要降低JIT编译的可用阈值,通过查看与JIT相关的参数即可明白,我们可以暂时使用JIT编译。
首先,创建一个用于测试使用JIT编译的表格。
CREATE TABLE jit_test (a INTEGER, b TEXT);
INSERT INTO jit_test (a, b)
SELECT g, md5(g::text) FROM generate_series(1, 50000) AS g;
为了强制执行JIT编译,我们需要启用JIT编译并降低相关参数的阈值。
SET jit=on;
SET jit_above_cost=10;
SET jit_inline_above_cost=10;
SET jit_optimize_above_cost=10;
有了这个,就准备好使用JIT编译了。
在PostgreSQL 11中,JIT编译用于WHERE子句和聚合等功能。
(请参考以下手册中的详细信息)
-
- 32.1.1. JIT Accelerated Operations
- https://www.postgresql.org/docs/11/static/jit-reason.html#JIT-ACCELERATED-OPERATIONS
因此,我們會在SQL語句中添加適當的WHERE子句,並執行該語句以查看執行計劃。
EXPLAIN ANALYZE SELECT * FROM jit_test WHERE a%2 = 1;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------
Seq Scan on jit_test (cost=0.00..1167.00 rows=250 width=37) (actual time=71.657..77.408 rows=25000 loops=1)
Filter: ((a % 2) = 1)
Rows Removed by Filter: 25000
Planning Time: 0.044 ms
JIT:
Functions: 2
Options: Inlining true, Optimization true, Expressions true, Deforming true
Timing: Generation 0.443 ms, Inlining 50.772 ms, Optimization 12.781 ms, Emission 7.972 ms, Total 71.969 ms
Execution Time: 86.891 ms
(9 行)
「JIT:」从下面的行可以看出,使用了JIT编译。
由于此次强行降低了阈值并使用了JIT编译,因此性能下降了与未使用JIT编译时相比。
这是因为超出开销的成本超过了JIT编译的加速效果。
接下来,我们将在下一节中调查和验证JIT编译在实际情况下的有效性。
我试图验证性能。
JIT编译执行查询不一定比常规查询执行快。
如果由于JIT编译导致的开销增加,它可能比常规查询更慢。
主要适用于由于CPU成为瓶颈而需要提速的查询,而I/O方面没有问题。
换句话说,适合包含复杂聚合或计算处理的SQL处理。
因此,我们选择了TPC-H基准测试进行本次测试。
引入TPC-H基准测试
TPC-H基准测试可以从TPC的网站上获得。
但是由于没有为PostgreSQL进行配置,因此需要进行调整。
本文将不介绍安装步骤。
如果您想了解更多详细信息,请参考参考网站上关于TPC-H的PostgreSQL安装链接。
本次我们使用了10GB的测试数据进行验证。
./dbgen -s 10
我们创建了以下环境用于验证。(由于TPC-H提供的SQL假设了TPCD模式中存在对象)
=# CREATE ROLE tpcd;
=# ALTER ROLE tpcd LOGIN SUPERUSER CREATEROLE CREATEDB CONNECTION LIMIT -1 PASSWORD 'password';
=# CREATE DATABASE tpcd OWNER tpcd;
=# \c tpcd tpcd
=# CREATE SCHEMA tpcd;
另外,我們使用以下的虛擬環境來進行驗證。
根据JIT编译的有无进行性能比较。
我们将使用TPC-H的查询1来比较使用和不使用JIT编译的性能。
首先是不使用JIT编译的EXPLAIN ANALYZE结果。
默认情况下,JIT使用是关闭的,但为了更容易理解,我们特意将JIT设置为OFF。
=# SET jit=off;
=# explain analyze
select
l_returnflag,
l_linestatus,
sum(l_quantity) as sum_qty,
sum(l_extendedprice) as sum_base_price,
sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
avg(l_quantity) as avg_qty,
avg(l_extendedprice) as avg_price,
avg(l_discount) as avg_disc,
count(*) as count_order
from
lineitem
where
l_shipdate <= date '1998-12-01' - interval ':1' day
group by
l_returnflag,
l_linestatus
order by
l_returnflag,
l_linestatus
LIMIT 1;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=2437688.60..2437688.94 rows=1 width=236) (actual time=68884.525..68885.261 rows=1 loops=1)
-> Finalize GroupAggregate (cost=2437688.60..2437690.67 rows=6 width=236) (actual time=68884.524..68884.525 rows=1 loops=1)
Group Key: l_returnflag, l_linestatus
-> Gather Merge (cost=2437688.60..2437690.00 rows=12 width=236) (actual time=68884.493..68885.228 rows=4 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Sort (cost=2436688.57..2436688.59 rows=6 width=236) (actual time=68879.669..68879.670 rows=3 loops=3)
Sort Key: l_returnflag, l_linestatus
Sort Method: quicksort Memory: 27kB
Worker 0: Sort Method: quicksort Memory: 27kB
Worker 1: Sort Method: quicksort Memory: 27kB
-> Partial HashAggregate (cost=2436688.33..2436688.50 rows=6 width=236) (actual time=68879.633..68879.641 rows=4 loops=3)
Group Key: l_returnflag, l_linestatus
-> Parallel Seq Scan on lineitem (cost=0.00..1437019.25 rows=24991727 width=25) (actual time=2.905..13461.643 rows=19995278 loops=3)
Filter: (l_shipdate <= '1998-11-30 00:00:00'::timestamp without time zone)
Rows Removed by Filter: 73
Planning Time: 0.201 ms
Execution Time: 68885.341 ms
(18 行)
=# SET jit=on;
=# explain analyze
select
l_returnflag,
l_linestatus,
sum(l_quantity) as sum_qty,
sum(l_extendedprice) as sum_base_price,
sum(l_extendedprice * (1 - l_discount)) as sum_disc_price,
sum(l_extendedprice * (1 - l_discount) * (1 + l_tax)) as sum_charge,
avg(l_quantity) as avg_qty,
avg(l_extendedprice) as avg_price,
avg(l_discount) as avg_disc,
count(*) as count_order
from
lineitem
where
l_shipdate <= date '1998-12-01' - interval ':1' day
group by
l_returnflag,
l_linestatus
order by
l_returnflag,
l_linestatus
LIMIT 1;
QUERY PLAN
-------------------------------------------------------------------------------------------------------------------------------------------------------------------
Limit (cost=2437688.60..2437688.94 rows=1 width=236) (actual time=55654.800..55658.101 rows=1 loops=1)
-> Finalize GroupAggregate (cost=2437688.60..2437690.67 rows=6 width=236) (actual time=55278.626..55278.627 rows=1 loops=1)
Group Key: l_returnflag, l_linestatus
-> Gather Merge (cost=2437688.60..2437690.00 rows=12 width=236) (actual time=55278.556..55281.857 rows=4 loops=1)
Workers Planned: 2
Workers Launched: 2
-> Sort (cost=2436688.57..2436688.59 rows=6 width=236) (actual time=55262.481..55262.482 rows=3 loops=3)
Sort Key: l_returnflag, l_linestatus
Sort Method: quicksort Memory: 27kB
Worker 0: Sort Method: quicksort Memory: 27kB
Worker 1: Sort Method: quicksort Memory: 27kB
-> Partial HashAggregate (cost=2436688.33..2436688.50 rows=6 width=236) (actual time=55262.405..55262.413 rows=4 loops=3)
Group Key: l_returnflag, l_linestatus
-> Parallel Seq Scan on lineitem (cost=0.00..1437019.25 rows=24991727 width=25) (actual time=343.737..9535.259 rows=19995278 loops=3)
Filter: (l_shipdate <= '1998-11-30 00:00:00'::timestamp without time zone)
Rows Removed by Filter: 73
Planning Time: 0.415 ms
JIT:
Functions: 35
Options: Inlining true, Optimization true, Expressions true, Deforming true
Timing: Generation 8.490 ms, Inlining 323.187 ms, Optimization 678.813 ms, Emission 392.651 ms, Total 1403.141 ms
Execution Time: 55708.158 ms
(22 行)
经过JIT编译,我们可以看到性能得到了改进。(虽然由于环境原因,不会明显变快…)
下面是每个方法执行5次时的比较结果。
通过使用JIT编译,可以加速执行复杂计算的SQL查询,尤其是在具备更大内存和CPU的环境下,JIT编译的影响会进一步增强。
参考网站
即时编译的详细信息和基准测试
-
- PGCon 2017 (JIT-Compiling SQL Queries in PostgreSQL Using LLVM)
-
- https://www.pgcon.org/2017/schedule/events/1092.en.html
-
- PGConf 2017におけるJITコンパイルの講演です。
-
- 従来との違いや、JITコンパイルの目的など詳しい情報が載っています。
PostgreSQL 11 and Just In Time Compilation of Queries
https://www.citusdata.com/blog/2018/09/11/postgresql-11-just-in-time/
JITコンパイルによるベンチマークテストの結果が載っています。
构建和验证系统
-
- PostgreSQL 11 検証報告
-
- https://www.sraoss.co.jp/tech-blog/pgsql/pg11report/
-
- (→3.3.1. JIT コンパイルを使うためのビルド使うためのビルドうためのビルド)
-
- PostgreSQL 11の様々な検証結果が載っています。
-
- とりあえず11で何かできるのか、を知りたい方にオススメです。
KKIDA-GALAXY [PostgreSQL11のJITコンパイリングを試す]
http://kkida-galaxy.blogspot.com/2018/04/postgresql11-with-jit-01.html
JITコンパイル環境を構築手順として、実行コマンドとその結果など詳細に説明されています。
環境構築が上手くいかない方は、こちらをじっくりと参照すると良いと思います。
How to compile PostgreSQL 11 with support for JIT compilation on RHEL/CentOS 7
https://blog.dbi-services.com/how-to-compile-postgresql-11-with-support-for-jit-compilation-on-rhelcentos-7/
海外のサイトですが、今回の記事を執筆するに辺り、大変参考になりました。
導入手順からテスト方法まで丁寧に記載されています。
重要なコマンドとその結果は載っているため、英語が苦手な方もGoogle翻訳を利用すれば簡単に理解可能です。
PostgreSQL 11に搭載されるJITコンパイラ機能を動かしてみる
https://debug-life.net/entry/2928
構築から検証まで丁寧に記載されており、なにより参考情報が豊富です。
(参考にしたPostgreSQLのソース先も紹介されています)
在中国引入TPC-H的PostgreSQL。
-
- TPC
-
- http://www.tpc.org/default.asp
-
- TPCの公式ページです。TPC-Hをはじめとしたベンチマークテストの入手やその説明文書が手に入ります。
PostgreSQL 9.6 with Parallel Query vs. TPC-H
http://rhaas.blogspot.com/2016/04/postgresql-96-with-parallel-query-vs.html
PostgreSQL 9.6上でTPC-Hの実施検証が載っています。リンク先のGitにPostgreSQL向けのTPC-Hクエリや、PostgreSQLへの導入方法など載っています。
DBGENを使って、PostgreSQLにTPC-H測定用データを格納
TPC-HをPostgreSQL上で実施する方法について、日本語で提供された情報です。
TPC-H Queries on PostgreSQL
http://myfpgablog.blogspot.com/2016/08/tpc-h-queries-on-postgresql.html
PostgreSQL上でTPC-Hを実施するための手順について記載されています。PostgreSQL向けに変換したSQLも載っています。