1. はじめに
先日、世界中の携帯基地局(約4,327万件)を3Dの地球儀(グローブ)に描くアプリを、Cloud Run と ClickHouse で作った話を書きました1。あの記事の最後で「そもそも、なぜ ClickHouse だとこれが速いのか」を別記事で確かめると予告していました。本記事がその続きです。
やることはシンプルです。グローブで使った cell_towers(4,327万件・基地局の緯度経度などが入った実データ)を、ClickHouse と Postgres の両方に入れて、まったく同じ集計を投げて比べるだけです。さらに、managed Postgres にプリインストールされている拡張 pg_clickhouse を使って、「Postgres につないだまま、同じ SQL で集計だけを ClickHouse に投げる」とどうなるかも見ます。
先に、ほかの記事との違いを書いておきます。pg_clickhouse の本格的なベンチマークは、以前 TPC-H 22 本を SF1 / SF10 の 2 規模で測った別記事2があります。データ量を上げると倍率が逆転する、という厳密な比較はそちらに任せます。本記事はあくまで グローブ記事の続きで、実データ1本を3者(Postgres 単体 / 直 ClickHouse / pg_clickhouse 経由)で軽く比べてみる「やってみた」 です。
先に結論です。
- 同じ
cell_towers4,327万件を両エンジンに入れ、同じ集計をフルスキャンで比べた。radio(通信方式)だけを数える集計は ClickHouse が約 18 倍速、緯度経度を丸めるグリッド集計でも約 2.4 倍速だった - しかも今回は ClickHouse の方が小さいインスタンス(3 スレッド)、Postgres は 4 vCPU でメモリにキャッシュ済み(ウォーム) という、Postgres に有利な土俵での結果
- 差を生むのは 読むデータ量。列指向の ClickHouse は必要な列だけ読む(
radioなら 43 MB)。行指向の Postgres はradio1 列を数えるだけでも全 5.3 GB を読む -
pg_clickhouseを使うと、Postgres につないだまま、同じ SQL で集計だけを ClickHouse にプッシュダウンでき、直 ClickHouse とほぼ同速だった - ただし、グローブが速い本当の理由はこの比較ではない。あれは H3 で事前集約しておいたからで、本記事は「生データへその場で集計をかけたら」という別の話
2. 検証環境
| 項目 | 内容 |
|---|---|
| ClickHouse | ClickHouse Cloud 26.2.1.474(小型・max_threads=3、AWS ap-northeast-1。グローブ記事と同じ CHTEST) |
| Postgres | ClickHouse-managed Postgres 18.4(4 vCPU / 16 GB、cell_towers の実サイズ 5,371 MB) |
| 拡張 |
pg_clickhouse 0.3(clickhouse_fdw、driver = binary) |
| データ |
cell_towers 43,276,150 行(両エンジンに同じデータを投入)3
|
| クライアント | WSL(Ubuntu)から psql と curl |
cell_towers は ClickHouse 公式のサンプルデータセットで3、世界中の基地局の位置(緯度・経度)と通信方式(radio 列)などが入っています。グローブ記事ではこれを ClickHouse に入れて使っていたので、今回はそれを Postgres 側にもコピーして、同じ土俵を作りました。
今回はあえて Postgres に有利な条件 で測っています。ClickHouse は小型インスタンス(3 スレッド)なのに対し、Postgres は 4 vCPU です。さらに Postgres 側の数値はウォーム(投入直後+連続実行でテーブルが RAM にキャッシュ済み)で、ディスクから 5.3 GB を読み直すコールド状態ならもっと遅くなります。つまり以下の差は「Postgres に手加減した状態でも、これだけ開く」という読み方になります。
3. やり方
3.1. 同じデータを Postgres にも入れる
ClickHouse 側にある cell_towers を、そのまま Postgres にコピーします。ClickHouse から CSV でストリーム出力し、Postgres の \copy で流し込むだけです(4,327万件で約 79 秒でした)。Postgres 側のテーブルは ClickHouse と同じ 14 列で作ってあります。型は素直に対応させ、ClickHouse の Enum8(radio)は text、DateTime(created / updated)は timestamp、Float64(lon / lat)は double precision にマッピングしました。
-- Postgres 側のテーブル定義(ClickHouse と同じスキーマ)
CREATE TABLE cell_towers (
radio text,
mcc integer,
net integer,
area integer,
cell bigint,
unit integer,
lon double precision,
lat double precision,
range_m bigint,
samples bigint,
changeable smallint,
created timestamp,
updated timestamp,
average_signal smallint
);
3.2. 比べる集計は2種類
性格の違う集計を 2 つ用意しました。どちらも 4,327万件をフルスキャンします。
-
radioだけを数える集計(I/O が支配的)。14 列のうちradio1 列しか触らない、いちばん列指向で差が出そうなクエリ -
緯度経度を丸めるグリッド集計(CPU 寄り)。
round()で緯度・経度を整数に丸め、radioと合わせて件数を数える。行ごとに浮動小数の丸め計算が走る
-- (1) radio だけを数える(I/O 支配)
SELECT radio, count(*) FROM cell_towers GROUP BY radio ORDER BY 2 DESC;
-- (2) 緯度経度を丸めるグリッド集計(CPU 寄り)
SELECT count(*) FROM (
SELECT round(lat) AS glat, round(lon) AS glon, radio, count(*) AS c
FROM cell_towers GROUP BY glat, glon, radio
) t;
クエリ本文は両エンジンでほぼ同じ(ClickHouse は count())にして、エンジンの違いだけが出るようにしました。Postgres 側は work_mem=256MB・並列 4 で、各クエリ 3 回ずつ実行した平均を取っています。
3.3. pg_clickhouse の外部テーブルを作る
pg_clickhouse は、ClickHouse のテーブルを Postgres から「外部テーブル」として参照できるようにする拡張です4。Postgres 側で集計を書くと、その集計を ClickHouse へプッシュダウン(ClickHouse 側で実行させる)してくれます。
managed Postgres にはこの拡張がプリインストールされているので、外部サーバ・ユーザーマッピング・外部テーブルを定義するだけで使えます。今回は読み取り専用ユーザーで動かすため、IMPORT FOREIGN SCHEMA(システム表の参照が要る)は使わず、必要な列だけを手で定義しました。
-- pg_clickhouse のセットアップ(ホスト名・認証情報は環境ごとに置き換え)
CREATE EXTENSION IF NOT EXISTS pg_clickhouse;
CREATE SERVER chtest_srv FOREIGN DATA WRAPPER clickhouse_fdw
OPTIONS (driver 'binary', host 'xxxxxxxx.ap-northeast-1.aws.clickhouse.cloud', dbname 'default');
CREATE USER MAPPING FOR CURRENT_USER SERVER chtest_srv
OPTIONS (user 'app_ro', password 'xxxxxxxx');
CREATE SCHEMA ch;
CREATE FOREIGN TABLE ch.cell_towers (
radio text OPTIONS(column_name 'radio'),
lon double precision OPTIONS(column_name 'lon'),
lat double precision OPTIONS(column_name 'lat')
) SERVER chtest_srv OPTIONS(table_name 'cell_towers');
これで ch.cell_towers を、Postgres のローカルテーブルと同じ感覚で集計できます。driver 'binary' は ClickHouse のネイティブプロトコル(9440/TLS)を使う指定で、Cloud のホストなら TLS は自動で有効になります。
3 つの経路を図にすると次のとおりです。psql から見ると、Postgres 単体と pg_clickhouse はどちらも「同じ Postgres へ同じ SQL を投げる」だけで、参照するテーブルが違うだけです。
ClickHouse 側の IP アクセスリストには、接続してくる Postgres の送信元 IP を許可しておく必要があります(pg_clickhouse のクエリは Postgres サーバ側から ClickHouse へ出ていくため)。この IP を登録していないと、TLS 確立の段階で接続が拒否されます。詳しい向きの話は TPC-H 記事2で扱っています。
4. 結果
4.1. radio だけを数える集計(I/O 支配)
radio 1 列を数えるだけの集計です。ClickHouse は radio 列しか読まないのに対し、Postgres は行指向なので「radio 1 列が欲しいだけ」でも行をまるごと(=全列ぶん)読みます。SELECT * をしていなくてもそうなります。行指向では 1 行ぶんの全列がディスク上でひとかたまりに並んでいるため、radio の値だけを取り出そうとしても、その行の他の列のバイトも一緒に読み込むことになるからです(どちらのエンジンも 43,276,150 行すべてを数える点は同じで、違うのは「1 行あたり何バイト読むか」です)。
| エンジン | 実行時間(3回平均) | 読んだ量 |
|---|---|---|
| Postgres | 1.67 s | 5.3 GB(全列) |
| ClickHouse | 0.09 s | 43 MB(radio 列のみ) |
約 18 倍速でした。読むデータ量は 5.3 GB 対 43 MB と、約 120 倍の差があります。Postgres がウォーム(メモリ上)でこの差なので、ディスクから読むコールドならさらに開きます。
なお radio の内訳はこうなっていて、グローブ記事で「5G(NR)が世界で 867 件しかない」と書いたのと同じデータです。
| radio | 件数 |
|---|---|
| UMTS(3G) | 20,686,487 |
| LTE(4G) | 12,101,148 |
| GSM(2G) | 9,931,304 |
| CDMA | 556,344 |
| NR(5G) | 867 |
4.2. グリッド集計(CPU 寄り)
緯度経度を round() で丸めるグリッド集計です。行ごとに浮動小数の丸め計算が入るので、I/O だけでなく CPU の重さも乗ってきます。
| エンジン | 実行時間(3回平均) | 読んだ量 | 結果グループ数 |
|---|---|---|---|
| Postgres | 7.66 s | 5.3 GB(全列) | 28,811 |
| ClickHouse | 3.13 s | 735 MB(lat / lon / radio の3列) | 28,981 |
約 2.4 倍速に縮みました。差が縮むのは、round() の浮動小数演算が行あたり重く、CPU 側の処理が支配的になるためです。それでも、小型インスタンスの ClickHouse が 4 vCPU の Postgres より速いままでした。列指向の I/O 優位は、読んだ量(735 MB 対 5.3 GB)にはっきり出ています。
ここでいう結果グループ数とは、round() で丸めた緯度・経度と radio の組み合わせが何通りできたか(=でき上がったグリッドのマス目の数)です。この数が Postgres と ClickHouse で少し違う(28,811 対 28,981)のは誤差ではなく、5 章の「プッシュダウンの証拠」につながります。
4.3. pg_clickhouse:Postgres につないだまま ClickHouse 速度
外部テーブル ch.cell_towers を経由して、まったく同じ集計を Postgres から投げます。集計は ClickHouse にプッシュダウンされます。
| クエリ | Postgres 単体 | pg_clickhouse(PG→CH プッシュダウン) | 直 ClickHouse | 倍率(Postgres 比) |
|---|---|---|---|---|
radio 集計 |
1.67 s | 0.092 s | 0.09 s | 約 18 倍 |
| グリッド集計 | 7.66 s | 3.13 s | 3.13 s | 約 2.4 倍 |
pg_clickhouse 経由は、直 ClickHouse とほぼ同速でした。上乗せされるのは数ミリ秒〜結果転送ぶんだけで、「Postgres の接続・SQL のまま、分析だけ ClickHouse 速度」が成り立っています。アプリ側は Postgres につなぎっぱなしで、重い集計だけ列指向エンジンに任せられる、という形です。
5. プッシュダウンの証拠
「速かった」だけでは、本当に ClickHouse 側で集計が走ったのか(Postgres 側で処理しただけではないか)は分かりません。これを確かめる手がかりが、さきほどの グリッド集計のグループ数 です。
| 経路 | グリッド集計のグループ数 |
|---|---|
| Postgres 単体 | 28,811 |
| 直 ClickHouse | 28,981 |
| pg_clickhouse 経由 | 28,981 |
同じ round() を使ったのに、Postgres 単体と ClickHouse でグループ数が少し違います(28,811 対 28,981、約 0.6%)。データ件数は同じ(どちらも 43,276,150 行)で、後で見るとおり丸めの計算結果も両エンジンでビット単位まで一致しています。差が出るのは、整数グリッドに丸めたあとに GROUP BY が「マイナスのゼロ」をどう扱うかという仕様差で、赤道・本初子午線の直下のマス目が ClickHouse 側でだけ 2 つに割れるためです。詳しい切り分けは 6.5 章で扱います。
ここで大事なのは、5章の主役であるプッシュダウンの証拠です。pg_clickhouse 経由のグループ数は 28,981 で、Postgres 単体(28,811)ではなく直 ClickHouse と一致しました。もし Postgres が手元で集計していたら 28,811 になるはずなので、この一致が「集計は ClickHouse 側で実行された」ことを示します。
より直接的には、EXPLAIN (VERBOSE) の Remote SQL: 行に集計(GROUP BY や round)が含まれるかでプッシュダウンを確認できます。その手順は TPC-H 記事2に載せたので、本記事ではより手軽なグループ数の一致で確かめました。
6. 考察
6.1. 列指向で差が大きいのは「I/O が支配的」なとき
今回の 2 つの集計で、差の大きさがはっきり分かれました。
-
radio集計(約 18 倍): 14 列のうち 1 列しか要らない。列指向はradioの 43 MB だけ読み、行指向は全 5.3 GB を読む。読むデータ量の差がそのまま速度差になる - グリッド集計(約 2.4 倍): 3 列を読み(735 MB)、さらに行ごとに
round()の計算が走る。読む量の差は残るが、CPU の重さが乗ってきて差が縮む
つまり、列指向(ClickHouse)が大きく差をつけるのは、必要な列が少なく、I/O が支配的なクエリです。逆に、全列を触る・行ごとの計算が重いクエリほど差は縮みます。それでも今回は小型インスタンス側が勝っていますが、これは「列指向だから常に何倍も速い」ではなく「読む量を減らせるクエリで差が出る」と読むのが正確だと考えられます。
6.2. pg_clickhouse の価値は「速さ」より「つなぎ替えずに済む」こと
pg_clickhouse 経由が直 ClickHouse とほぼ同速だったのは、集計が丸ごと ClickHouse にプッシュダウンされ、Postgres へ戻る行が集計後の少数だけになるからです。アプリから見ると、接続先を Postgres のままにして、重い分析クエリだけ ClickHouse に処理させられるのが利点です。
ただし、純粋な分析クエリだけなら、直接 ClickHouse に問い合わせる方が外部テーブルの往復ぶん速いはずです。pg_clickhouse の本質的な価値は「速さそのもの」より「Postgres という1つの入口に統合できること」にあると考えられます。どんなクエリでもプッシュダウンされるわけではない点(相関サブクエリなどは行ごとに往復して不利になる)は、TPC-H 22 本で細かく分類した別記事2に譲ります。
6.3. 注記:この比較が「フェア」ではない点
最後に、この数字をそのまま受け取らないための注記です。
- ClickHouse は小型(3 スレッド)、Postgres は 4 vCPU。CPU 資源では Postgres の方が有利な土俵
- Postgres の数値はウォーム(メモリにキャッシュ済み)。コールドでディスクから 5.3 GB 読めばもっと遅くなる
- それでも ClickHouse が 18 倍 / 2.4 倍速い、という読み方になる
そして最も大事な注記です。グローブアプリが速かった本当の理由は、今回の比較とは別です。あのアプリは cell_towers_h3 という事前集約テーブルを引いていて、ブラウザに返すのは数千行だけでした(ClickHouse 側は 1 桁ミリ秒)。この集約テーブルは約 185 万行・30 MiB と小さく、これくらいの大きさなら列指向でなくても軽いので、Postgres 単体でも対話的に返せると考えられます(Postgres は削除済みで今回は未実測)。つまりグローブの速さの本体は、列指向そのものよりも事前集約にあります。本記事は「事前集約せず、生の 4,327万件にその場で集計をかけたら」という、もう一段手前の話です。事前に集約できるなら集約が一番速いですし、できない・その場で集計したいときに列指向のフルスキャンで差が出る、という使い分けになります。
6.4. pg_clickhouse から事前集約テーブルも指せる
ここまでの pg_clickhouse は生データ cell_towers を外部テーブルにして比べました。では、グローブが速い理由だった事前集約テーブル cell_towers_h3 は pg_clickhouse から使えないのでしょうか。
これは使えます。外部テーブルは参照先の ClickHouse テーブルを名前で指すだけなので、OPTIONS(table_name 'cell_towers_h3') に変えれば、Postgres から事前集約テーブルをそのまま引けます。cell_towers_h3 は約 185 万行・30 MiB(生データは ClickHouse 上 1.07 GiB)と小さく、解像度や radio で絞ればさらに読む量が減ります。
-- 事前集約テーブルを指す外部テーブル(3.3 と同様、必要な列だけ手動定義)
CREATE FOREIGN TABLE ch.cell_towers_h3 (
h3_res smallint OPTIONS(column_name 'h3_res'),
radio text OPTIONS(column_name 'radio'),
cnt bigint OPTIONS(column_name 'cnt'),
center_lon double precision OPTIONS(column_name 'center_lon'),
center_lat double precision OPTIONS(column_name 'center_lat')
) SERVER chtest_srv OPTIONS(table_name 'cell_towers_h3');
つまり pg_clickhouse は「列指向の速さ(4 章)」と「事前集約の速さ(グローブ)」のどちらも引き出せます。アプリは Postgres につないだまま、重い集計を ClickHouse の事前集約テーブルに任せれば、グローブと同じ 1 桁ミリ秒級(前記事の解像度 3 で ClickHouse 側約 9 ミリ秒1)を Postgres の SQL から引き出せると考えられます。今回は生データの比較が主眼で、この経路の実測まではしていません。
6.5. 同じ SQL でも結果が食い違った原因(-0.0 の GROUP BY 扱い)
5章のグループ数の差(28,811 対 28,981)は、「同じ SQL でも、どのエンジンで実行するかで結果が変わりうる」ことの小さな実例です。原因も調べました。丸めルールの違いではなく、GROUP BY が「マイナスのゼロ(-0.0)」をどう扱うかの違いでした。丸めそのものは両エンジンとも同じで(PostgreSQL の round(double precision) は rint() を呼ぶだけ5、ClickHouse も同じ「バンカー丸め」=ちょうど .5 のときは近い方の偶数へ丸める方式です6。round(0.5) は 0、round(2.5) は 2)、ローカルの PostgreSQL 18.4 に同じデータを入れ直してもビット単位まで一致しました。差が出るのは、緯度・経度が -0.5〜0 の点(赤道のすぐ南/本初子午線のすぐ西)が round() で -0.0 になるところです。ClickHouse は GROUP BY で -0.0 と +0.0 を別キーにする7のでマス目が 2 つに分かれて 28,981、PostgreSQL は -0.0 を +0.0 に正規化して同じキーにまとめる8ので 28,811 になります(ClickHouse 側で + 0.0 を足して正規化すると 28,811 に一致しました)。
これは公式も正面から扱っています。ClickHouse は pg_clickhouse の設計で、プッシュダウンを性能最適化ではなく「正しさの契約」と位置づけ、「各式が結果を変えずに翻訳できることを検証し、できなければエラーにする」「差が出ると判明したプッシュダウンは撤回する」としています9。PostgreSQL の postgres_fdw も同じ思想で、ローカルとリモートで同じ結果になると確信できる関数・演算子だけを押し下げ、列はリモートと同じ型・照合順序で宣言せよ(ずれると意味の食い違いが起きうる)と警告しています10。
6.6. どこで結果が食い違うか(クロスエンジン/Zero-ETL の要検証リスト)
この「同じ SQL でも結果が食い違う」現象は ClickHouse 固有ではなく、エンジンをまたぐとき全般に起きます。形は 2 つに分けると整理しやすくなります。
-
フェデレーテッド/プッシュダウン型(
pg_clickhouse、Redshift Spectrum、Athena など): 1 つのクエリが 2 エンジンにまたがり、関数がどう翻訳(プッシュダウン)されるかで結果が食い違う - レプリケーション/Zero-ETL 型(Aurora/RDS PostgreSQL → Redshift の Zero-ETL、CDC、今回の CH→CSV→PG): データを別エンジンの型に移してから、移し先のエンジンの仕様で集計する。型の対応づけと集計時の挙動の 2 段でずれる余地がある
今回の検証は、実はこの両方に当てはまります(CH→CSV→PG の移送が後者、pg_clickhouse のプッシュダウンが前者)。
無秩序に違いが出るわけではなく、差が出やすい箇所はだいたい決まっています。代表的なカテゴリを「要検証リスト」として持っておくと確認しやすくなります。
| カテゴリ | 例 |
|---|---|
| 浮動小数のエッジ |
-0.0/+0.0、NaN の同値・順序、SUM(float) が足し込み順序で変わる(同一エンジンでも揺れうる) |
| 文字列の照合・空白 | 並び順・大小比較・DISTINCT/GROUP BY がロケール依存。末尾空白の扱いもエンジンで違う |
| NULL | 集計での扱い、ORDER BY の NULLS FIRST/LAST の既定、DISTINCT と NULL |
| 日付・時刻 | タイムゾーン、timestamp と timestamptz、週/四半期の関数、境界の丸め |
| 数値・キャスト | 精度・スケール、整数除算、オーバーフロー、キャスト時に丸めか切り捨てか、ゼロ除算(エラー/NULL/inf) |
| 制約・一意性 | 一意制約を強制しないエンジンがある(宣言できても守られない)。「重複はないはず」の前提がずれる |
今回の -0.0 は、この表の「浮動小数のエッジ」の一例です。他のエンジンで同じことが起きるかは未確認です。たとえば Amazon Redshift も PostgreSQL ベースですが列指向で設計が異なり、サポートしない関数・型・機能が公式に整理されています11。Zero-ETL(PostgreSQL → Redshift)では、これに加えて取り込み時の型の対応づけ(NUMERIC の精度、TIMESTAMPTZ、TEXT が移し先でどの型・精度になるか)でもずれることがあります12。
守り方はシンプルです。「同じ SQL なら同じ結果」と決めつけず、代表的なクエリで native と結果を突き合わせて確かめます。とくに float キーの GROUP BY/COUNT(DISTINCT)、文字列の並び・重複、日付の境界、SUM(float) の桁は差が出やすい箇所です。監査・課金・件数レポートのように数字が一致してほしい用途では、移行や Zero-ETL の受け入れテストにこの照合を入れておくと安全です。
7. まとめ
| 観点 | 結論 |
|---|---|
| radio 集計(I/O 支配) | ClickHouse が約 18 倍速(読む量 43 MB 対 5.3 GB) |
| グリッド集計(CPU 寄り) | ClickHouse が約 2.4 倍速(差は縮むが小型側が勝つ) |
| 差を生む要因 | 列指向は必要な列だけ読む。行指向は1列だけ欲しくても行まるごと(全列ぶん)読む |
| pg_clickhouse | Postgres につないだまま、集計だけ ClickHouse にプッシュダウン=直 ClickHouse とほぼ同速 |
| 前提 | ClickHouse 小型・Postgres ウォームと、むしろ Postgres 有利の条件での結果 |
グローブが速い理由を確かめるために、同じ 4,327万件を Postgres と ClickHouse で集計して比べてみました。列指向は「必要な列だけ読む」ので、I/O が支配的なクエリほど差が開くこと、pg_clickhouse を使えば Postgres の接続のまま重い集計を ClickHouse に処理させられることが、実データ 1 本でも体感できました。
より厳密な、データ規模を変えながらの倍率の動きは TPC-H 記事2に、グローブアプリそのものの作り方は前記事1にまとめています。
8. 参考
-
前記事(グローブアプリ)。Cloud Run + ClickHouse で 4,327万件の基地局を3Dグローブに描いた話。本記事はその「なぜ速いのか」編です。https://qiita.com/asahide/items/13963fedf72d4d30a461 ↩ ↩2 ↩3
-
pg_clickhouse の本格ベンチ記事。TPC-H 22 本を SF1 / SF10 で測り、データ量で倍率が逆転することを実測。https://qiita.com/asahide/items/cb1af815777bb4f15bb6 ↩ ↩2 ↩3 ↩4 ↩5
-
ClickHouse ドキュメント「Cell Towers」サンプルデータセット。https://clickhouse.com/docs/getting-started/example-datasets/cell-towers ↩ ↩2
-
pg_clickhouse公式リポジトリ(ClickHouse 開発、Apache 2 ライセンス。旧clickhouse_fdwの後継)。本記事はマネージド Postgres に同梱の 0.3 で検証。最新の対応関数・仕様は GitHub を参照。https://github.com/ClickHouse/pg_clickhouse ↩ -
PostgreSQL ソース
src/backend/utils/adt/float.cのdround()(PostgreSQL 18)。round(double precision)はrint(arg1)を返すだけで、丸めはデフォルトの浮動小数モード(最も近い偶数へ)に従う。https://github.com/postgres/postgres/blob/REL_18_STABLE/src/backend/utils/adt/float.c ↩ -
PostgreSQL ドキュメント「8.1. Numeric Types」。
numericは 0 から遠い側へ、real/double precisionは(多くの環境で)最も近い偶数へ丸める。https://www.postgresql.org/docs/current/datatype-numeric.html ↩ -
ClickHouse は
-0.0 = +0.0を1(等しい)と判定する一方、GROUP BY / DISTINCT /uniqExactなどの集合系操作ではキーをバイト単位で比べるため、-0.0と+0.0を別グループにする(既知の挙動。+ 0.0を足すなどで正規化すると併合できる)。https://github.com/ClickHouse/ClickHouse/issues/51513 ↩ -
PostgreSQL ソース
src/backend/access/hash/hashfunc.cのhashfloat8()(PostgreSQL 18)。「minus zero and zero ... should compare as equal」というコメントとともに、if (key == (float8) 0) PG_RETURN_UINT32(0);で-0.0を+0.0と同じハッシュに正規化する。このため GROUP BY や DISTINCT では-0.0と+0.0が同じグループになる。https://github.com/postgres/postgres/blob/REL_18_STABLE/src/backend/access/hash/hashfunc.c ↩ -
ClickHouse Blog「Postgres FDW: Pushdown is a negotiation」。プッシュダウンを「正しさの契約」と位置づけ、結果が変わるものは撤回する、と説明。https://clickhouse.com/blog/postgres-fdw-pushdown-negotiation ↩
-
PostgreSQL ドキュメント「F.38. postgres_fdw」。ローカルとリモートで同じ結果になると確信できる場合だけプッシュダウンする旨、および型・照合順序が一致しないと意味の食い違いが起きうる旨の警告。https://www.postgresql.org/docs/current/postgres-fdw.html ↩
-
AWS ドキュメント「Amazon Redshift and PostgreSQL」。Redshift は PostgreSQL ベースだが列指向で設計が異なり、未サポートの関数・型・機能がある旨を整理。https://docs.aws.amazon.com/redshift/latest/dg/c_redshift-and-postgres-sql.html ↩
-
AWS ドキュメント「Data type differences between Amazon Redshift and supported PostgreSQL and MySQL databases」。Zero-ETL / フェデレーテッドクエリでの型マッピングの違い。https://docs.aws.amazon.com/redshift/latest/dg/federated-data-types.html ↩