为什么 ClickHouse 字典性能这么低?
Why is ClickHouse dictionary performance so low?
我在 PostgreSql 数据库中有一个带有产品名称的 table。总行数约为 30M。我在 ClickHouse 中有价格的历史记录。我想将名称与价格结合起来。
DDL 创建字典:
CREATE DICTIONARY products_dict
(
product_id String,
name String
)
PRIMARY KEY product_id
SOURCE(POSTGRESQL(
...
query 'SELECT product_id, name FROM products'
))
LAYOUT(COMPLEX_KEY_HASHED())
LIFETIME(3600);
然后我有字典:
database: wdm
name: products_dict
uuid: 1464ba09-990c-4e69-9464-ba09990c0e69
status: LOADED
origin: 1464ba09-990c-4e69-9464-ba09990c0e69
type: ComplexKeyHashed
key.names: ['product_id']
key.types: ['String']
attribute.names: ['name']
attribute.types: ['String']
bytes_allocated: 4831830312
query_count: 57912282
hit_rate: 1
found_rate: 1
element_count: 28956140
load_factor: 0.4314801096916199
source: PostgreSQL: ...
lifetime_min: 0
lifetime_max: 3600
loading_start_time: 2022-01-17 03:53:21
last_successful_update_time: 2022-01-17 03:54:46
loading_duration: 84.79
last_exception:
comment:
此外,我还有 table 这本词典:
-- auto-generated definition
create table products_dict
(
product_id String,
name String
)
engine = Dictionary;
当我查询这本词典时,大约需要 3 秒。
- 一个 id 与 WHERE IN
SELECT name FROM products_dict WHERE product_id IN ('97646221')
1 row retrieved starting from 1 in 2 s 891 ms (execution: 2 s 841 ms, fetching: 50 ms)
- 501个产品无条件排序
SELECT t.*
FROM products_dict t
LIMIT 501
500 rows retrieved starting from 1 in 2 s 616 ms (execution: 2 s 601 ms, fetching: 15 ms)
- 加入
SELECT ppd.*, p.name
FROM
(
SELECT
product_id,
price
FROM product_prices_daily
WHERE
product_id IN ('97646221','97646318','976464823','97647223','976472425','976474961','976476908')
AND day between '2022-01-13' and '2022-01-14'
) as ppd
LEFT JOIN products_dict as p ON p.product_id = ppd.product_id
4 rows retrieved starting from 1 in 6 s 984 ms (execution: 6 s 959 ms, fetching: 25 ms)
DBMS:ClickHouse(版本 21.12.3.32)
客户端:DataGrip 2021.3.2
服务器:128GB RAM,数十核,3TB SSD,无任何负载。
product_id 从 160 亿个 MergeTree table 中读取大约需要 100 毫秒。
我用 engine=dictionary 测试了手动创建的 table 并得到了相同的结果。
我不能使用平面布局,因为 product_id 是字符串。
Clickhouse-client 的另一个测试:
ch01 :) SELECT name FROM products_dict WHERE product_id IN ('97646239');
SELECT name
FROM products_dict
WHERE product_id IN ('97646239')
Query id: d4f467c9-be0e-4619-841b-a76251d3e714
┌─name──┐
│ ...│
└───────┘
1 rows in set. Elapsed: 2.859 sec. Processed 28.96 million rows, 2.30 GB (10.13 million rows/s., 803.25 MB/s.)
怎么了?
尚未实现此类优化。
最初假设词典只能与 dictGet
函数一起使用。
Table 表示法是后来引入的。
内部字典是哈希表的集合——如果您的字典有 50 个属性,那么它将是 50 个哈希表。如果您通过键查找,这些哈希表非常快,但如果您需要查找下一个元素,则非常慢。
现在查询 SELECT name FROM products_dict WHERE product_id IN ('97646239')
以非常直接的方式执行,尽管它可以在后台转换为 dictGet
。
我在 PostgreSql 数据库中有一个带有产品名称的 table。总行数约为 30M。我在 ClickHouse 中有价格的历史记录。我想将名称与价格结合起来。 DDL 创建字典:
CREATE DICTIONARY products_dict
(
product_id String,
name String
)
PRIMARY KEY product_id
SOURCE(POSTGRESQL(
...
query 'SELECT product_id, name FROM products'
))
LAYOUT(COMPLEX_KEY_HASHED())
LIFETIME(3600);
然后我有字典:
database: wdm
name: products_dict
uuid: 1464ba09-990c-4e69-9464-ba09990c0e69
status: LOADED
origin: 1464ba09-990c-4e69-9464-ba09990c0e69
type: ComplexKeyHashed
key.names: ['product_id']
key.types: ['String']
attribute.names: ['name']
attribute.types: ['String']
bytes_allocated: 4831830312
query_count: 57912282
hit_rate: 1
found_rate: 1
element_count: 28956140
load_factor: 0.4314801096916199
source: PostgreSQL: ...
lifetime_min: 0
lifetime_max: 3600
loading_start_time: 2022-01-17 03:53:21
last_successful_update_time: 2022-01-17 03:54:46
loading_duration: 84.79
last_exception:
comment:
此外,我还有 table 这本词典:
-- auto-generated definition
create table products_dict
(
product_id String,
name String
)
engine = Dictionary;
当我查询这本词典时,大约需要 3 秒。
- 一个 id 与 WHERE IN
SELECT name FROM products_dict WHERE product_id IN ('97646221')
1 row retrieved starting from 1 in 2 s 891 ms (execution: 2 s 841 ms, fetching: 50 ms)
- 501个产品无条件排序
SELECT t.*
FROM products_dict t
LIMIT 501
500 rows retrieved starting from 1 in 2 s 616 ms (execution: 2 s 601 ms, fetching: 15 ms)
- 加入
SELECT ppd.*, p.name
FROM
(
SELECT
product_id,
price
FROM product_prices_daily
WHERE
product_id IN ('97646221','97646318','976464823','97647223','976472425','976474961','976476908')
AND day between '2022-01-13' and '2022-01-14'
) as ppd
LEFT JOIN products_dict as p ON p.product_id = ppd.product_id
4 rows retrieved starting from 1 in 6 s 984 ms (execution: 6 s 959 ms, fetching: 25 ms)
DBMS:ClickHouse(版本 21.12.3.32) 客户端:DataGrip 2021.3.2 服务器:128GB RAM,数十核,3TB SSD,无任何负载。 product_id 从 160 亿个 MergeTree table 中读取大约需要 100 毫秒。 我用 engine=dictionary 测试了手动创建的 table 并得到了相同的结果。 我不能使用平面布局,因为 product_id 是字符串。
Clickhouse-client 的另一个测试:
ch01 :) SELECT name FROM products_dict WHERE product_id IN ('97646239');
SELECT name
FROM products_dict
WHERE product_id IN ('97646239')
Query id: d4f467c9-be0e-4619-841b-a76251d3e714
┌─name──┐
│ ...│
└───────┘
1 rows in set. Elapsed: 2.859 sec. Processed 28.96 million rows, 2.30 GB (10.13 million rows/s., 803.25 MB/s.)
怎么了?
尚未实现此类优化。
最初假设词典只能与 dictGet
函数一起使用。
Table 表示法是后来引入的。
内部字典是哈希表的集合——如果您的字典有 50 个属性,那么它将是 50 个哈希表。如果您通过键查找,这些哈希表非常快,但如果您需要查找下一个元素,则非常慢。
现在查询 SELECT name FROM products_dict WHERE product_id IN ('97646239')
以非常直接的方式执行,尽管它可以在后台转换为 dictGet
。