发布概要
新增29个新功能
实现了19项性能优化
修复了63处bug
以下是一些亮点功能...这次发布涵盖了向量的算术运算、tuple的连接、cluster/clusterAllReplicas的默认参数、从元数据中计数(对于Parquet来说速度提高了5倍)、文件内跳数(对Parquet有巨大提升)、从对象存储中流式消费数据,等等...
新贡献者
对于23.6版本的所有新贡献者,我们表示特别的欢迎!ClickHouse的受欢迎程度在很大程度上归功于贡献的社区。看到这个社区的增长总是令人感到振奋。
如果你在这里看到你的名字,请与我们联系。
AlKorgun,Zamazan4ik(AlexanderZaitsev),AndyFiddaman,ArturMalchanau,AshVardanian,AustinKothig,BhavnaJindal,BinXie,DaniPozo,DanielPozoEscalona,DaniëlvanEeden,DavitVardanyan,FilippOzinov,HendrikM,JaiJhala,JianfeiHu,JiangYuqing,JiyoungYoo,JoeLynch,KenjiNoguchi,KrisztiánSzűcs,LucasFernandoCardosoNunes,MaximilianRoos,NikitaKeba,PengyuanBian,RuslanMardugalliamov,Selfuppen,SergeKlochkov,SergeyKatkovskiy,TanayTummalapalli,VanDarkholme7,YuryBogomolov,cfanbo,copperybean,daviddhc20120601,ekrasikov,gyfis,hendrik-m,irenjj,jiyoungyoooo,jsc0218,justindeguzman,kothiga,nikitakeba,selfuppen,xbthink,xiebin,ИльяКоргун,王智博
源源不断的文件
更快的文件读取(MichaelKolupaev/PavelKruglov)
在近期的几次发布中,我们强调了为提高Parquet性能所做的努力[1][2]。虽然提高性能是一个永无止境的旅程,但23.8中的变化很重要,因为它们使我们对当前的Parquet文件读取性能更为满意。此外,这些提升中也适用于其他文件类型,如JSON和CSV。
总的来说,ClickHouse现在可以:
- 利用Parquet文件中的元数据跳过读取行组,该元数据存储了列值的范围。该特性提供了显著的速度提升,我们会在后面您展示。
- 利用元数据为大多数文件格式提供快速计数,包括Parquet,从而避免不必要的读取。
- 允许在过滤子句中使用文件名元数据来避免读取文件。当应用于对象存储上的大文件列表时,这可以避免大量的I/O,将查询从秒减少到毫秒。这项改进适用于所有文件类型。
为了说明这些增加功能可以带来的好处,我们将使用一个PyPI的数据集:Python包索引。这个数据集中的每一行代表使用如pip这样的工具下载一个Python包。我们提供了一个Parquet文件,其中包含了一天内所有包的下载数据。包括大约125.69GiB的Parquet数据,分布在1657个文件中,共有9亿行。
所有以下的测试都是在一个16核64G内存的实例上进行。
在23.8之前,在这些文件上进行计数操作很昂贵。从每个文件中下载无论多少列,都需要完整地读取,然后计算总数。在本地Macbook上运行时:
--23.7SELECTcount()FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet)┌───count()─┐│ 900786589 │└───────────┘1 row in set. Elapsed: 26.488 sec. Processed 900.79 million rows, 134.94 GB (34.01 million rows/s., 5.09 GB/s.)--23.8SELECT count()FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')1 row in set. Elapsed: 11.431 sec. Processed 900.79 million rows, 56.22 KB (78.80 million rows/s., 4.92 KB/s.)Peak memory usage: 44.43 MiB.
很好,性能提升了一倍以上!这种优化也适用于其他文件类型,因此它的好处应该超出Parquet文件范围。
这些相同的文件有一个表示下载发生时间的时间戳列。使用ParquetMetadata格式,我们可以看到有一列描述了最小值和最大值的元数据。
SELECT tupleElement(row_groups[1],'columns')[1]AStimestampFROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/000000000000.parquet', ParquetMetadata)FORMAT PrettyJSONEachRow
{"timestamp":{"name":"timestamp","path":"timestamp","total_compressed_size":"681","total_uncompressed_size":"681","have_statistics":1,"statistics":{"num_values":"406198","null_count":"0","distinct_count":null,"min":"1690761600000000","max":"1690761650000000"}}}
从23.8版本开始,我们可以在查询时利用这些元数据来加速查询。假设我们希望确定某天中30分钟内的下载次数。
--23.7SELECT project,count()AS c FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')WHERE(timestamp>='2023-07-31 15:30:00')AND(timestamp<='2023-08-31 16:00:00')GROUPBY project ORDERBY c DESCLIMIT5┌─project────────────┬───────c─┐ │ boto3 │ 9378319 │ │ urllib3 │ 5343716 │ │ requests │ 4749436 │ │ botocore │ 4618614 │ │ setuptools │ 4128870 │ └────────────────────┴─────────┘ 5 rows inset. Elapsed:83.644 sec. Processed 900.79 million rows,134.94 GB (10.77 million rows/s.,1.61 GB/s.)--23.8SELECT project,count()AS c FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')WHERE(timestamp>='2023-07-31 15:30:00')AND(timestamp<='2023-08-31 16:00:00')GROUPBY project ORDERBY c DESCLIMIT55 rows inset. Elapsed:34.993 sec. Processed 338.86 million rows,51.17 GB (9.68 million rows/s.,1.46 GB/s.)Peak memory usage:95.61 MiB.
又是一倍的性能提升!
这一特定的改进也立即影响了我们的ClickBench的结果,如下所示:
最后,Clickhouse长时间以来一直支持文件路径中的通配符模式。虽然这非常适合针对文件的子集,但它限制了用户使用通配符的表达能力。因此,ClickHouse暴露了一个_file虚拟列。这个隐藏列包含了一个行的来源文件名,并向用户显示。这可以在SQL查询的任何地方使用,例如用来计算唯一文件名的数量或限制读取的文件子集。但是,在23.7及更早版本中,如果在SELECT中使用了这一列,则需要读取整个文件。如果用户仅试图确定一个子集,这可能意味着需要读取所有文件。
这里的性能提升潜力可能非常大,并将取决于子集相对于文件总数的大小。考虑以下例子,我们计算一个10%样本的唯一文件数量。
--23.7SELECT uniq(_file)FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')WHERE(toUInt32(splitByChar('.', _file)[1])%10)=0┌─uniq(_file)─┐ │ 166 │ └─────────────┘ 1 row inset. Elapsed:4.572 sec. Processed 89.46 million rows,13.41 GB (19.57 million rows/s.,2.93 GB/s.)--23.8SELECT uniq(_file)FROM s3('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023-07-31/*.parquet')WHERE(toUInt32(splitByChar('.', _file)[1])%10)=0┌─uniq(_file)─┐ │ 166 │ └─────────────┘ 1 row inset. Elapsed:0.632 sec. Processed 89.46 million rows,0.00 B (141.65 million rows/s.,0.00 B/s.)Peak memory usage:1.71 MiB.
性能提高了7倍!请记住,这种特定的优化适用于所有文件类型,不仅仅是Parquet。
如果需要完整的路径,ClickHouse还提供了一个_path虚拟列。
从S3流式消费数据(SergeiKatkovskiy,KseniiaSumarokova)
从S3读取数据的能力是ClickHouse的一个关键功能,用于执行即席数据分析,可能也是把数据迁移到MergeTree表中最受欢迎的方法。虽然可以使用INSERTINTOSELECT和s3表函数来执行初始数据写入,但随后的增量数据通常需要用户额外的工作。可能是使用像Kafka之类的数据管道,或者更简单地,使用cronjob来调度一个INSERTSELECT。后者出奇地常见,并且很难保证稳定性。
在23.8版本中,我们开始使用S3Queue表引擎简化从S3的增量写入。这个新的表引擎允许从S3流式消费数据。当文件添加到一个bucket中时,ClickHouse将自动处理这些文件并将它们插入到指定的表中。有了这个功能,用户可以不需要额外的代码就可以设置简单的增量流水线。
考虑以下简单的例子。我们有一个bucket,其中包含PyPI数据集的Parquet文件,每个文件代表一个小时的数据。
CREATETABLE pypi_queue ENGINE = S3Queue('https://storage.googleapis.com/clickhouse_public_datasets/pypi/file_downloads/2023/*.parquet')SETTINGS mode ='unordered'CREATETABLE pypi ENGINE = MergeTree ORDERBY(project,timestamp)SETTINGS allow_nullable_key =1 EMPTY ASSELECT*FROM pypi_queue CREATE MATERIALIZED VIEW pypi_mv TO pypi ASSELECT*FROM pypi_queue SELECTcount()FROM pypi ┌──count()─┐ │ 39082124 │ └──────────┘ 1 row inset. Elapsed:0.003 sec.
熟悉Kafka表引擎的用户将会认出下面提到的结构。在这里,我们使用了一个物化视图来订阅S3Queue,并将转换后的结果插入到目标pypi表中。
如果我们向bucket中添加一个新文件,表格将会更新:
上述的S3Queue引擎通过定期轮询bucket并跟踪现有的文件来工作,同时在ClickHouseKeeper节点中存储状态。默认情况下,每次轮询时检索到的文件列表会与存储的列表进行对比,以识别新文件。下面的图示展示了如何处理一个新文件(并添加到Keeper)并插入到队列表中。虽然这并不存储数据本身,但物化视图可以订阅,并在行插入到表前和实现数据处理。
这代表了默认unordered的简化行为,用户可以进行调整。例如,用户可以配置引擎在导入文件后删除S3文件。这有助于从ClickHouseKeeper中移除状态,确保跟踪的状态不会无限制地增长。为了防止状态的无限制存储,引擎默认只跟踪有限数量的文件,并同时设置TTL。在文件的TTL到期或文件数量超过当前限制后,文件将被重新导入。用户可以调整这些限制,但我们建议使用删除功能或使用S3特性手动在bucket中过期文件。
另外,引擎可以配置为使用文件名称排序,在ordered模式下工作。在此模式下,Keeper只存储成功消费的文件中最大的名称。在每次轮询时,只有名称更高的文件会被导入。这需要在您的文件名中强加一个顺序,但可以避免上述的许多复杂性。
我们期待在接下来的几个月内改进这个功能,并希望我们已经稍微简化了您的架构。
直接从归档中导入(NikitaKeba,AntonioAndelic,PavelKruglov)
作为我们最后的功能亮点,并且仍然围绕文件主题,我们很高兴地宣布现在支持归档文件。ClickHouse已经支持如zstd、lz4、snappy、gz、xz和bz2等格式的压缩文件。在23.8版本之前,这些压缩文件只能包含一个文件。在23.8版本中,我们增加了对zip、tar和7zip的支持,这些格式都可能包含多个文件。
例如,我们提供了一个1.5GB的zip存档,其中包含24个CSV文件(未压缩下45GB),代表了一天的PyPI数据,共有9亿行。每一个文件都包含了以下列的PyPI数据集:project、version和timestamp,并表示了一个小时的数据。下面的查询使用虚拟列_file统计zip中每个文件的行数。注意我们如何使用::*语法查询存档中的所有文件。
目前只支持通过file表函数使用归档文件。因此,下面的操作是使用clickhouse-local执行的。要获得支持如S3的函数的支持,请继续关注!
SELECTcount(), _file FROM file('2023-08-01.zip :: *.csv')GROUPBY _file ┌──count()─┬─_file────────────────┐ │ 47251829 │ file_download_15.csv │ │ 43946206 │ file_download_17.csv │ │ 39082124 │ file_download_0.csv │ │ 38928391 │ file_download_21.csv │ │ 34467371 │ file_download_1.csv │ │ 44163805 │ file_download_12.csv │ │ 43229010 │ file_download_18.csv │ │ 41974421 │ file_download_10.csv │ │ 33003822 │ file_download_4.csv │ │ 33331289 │ file_download_23.csv │ │ 34430684 │ file_download_5.csv │ │ 40843622 │ file_download_11.csv │ │ 41122874 │ file_download_19.csv │ │ 37279028 │ file_download_6.csv │ │ 36118825 │ file_download_22.csv │ │ 40800076 │ file_download_7.csv │ │ 31962590 │ file_download_2.csv │ │ 42055283 │ file_download_20.csv │ │ 30887864 │ file_download_3.csv │ │ 45910953 │ file_download_13.csv │ │ 43467095 │ file_download_9.csv │ │ 46705311 │ file_download_16.csv │ │ 42704388 │ file_download_8.csv │ │ 48248862 │ file_download_14.csv │ └──────────┴──────────────────────┘ 24 rows inset. Elapsed:97.703 sec. Processed 961.10 million rows,48.57 GB (9.84 million rows/s.,497.11 MB/s.)Peak memory usage:4.04 MiB.
我们可以使用相同的::符号来定位特定的文件。
SELECT toStartOfMinute(timestamp)AS minute,count()AS c FROM file('2023-08-01.zip :: file_download_9.csv')WHERE project ='requests'GROUPBY project, minute ORDERBY minute ASC┌──────────────minute─┬─────c─┐ │ 2023-08-0109:00:00 │ 10944 │ │ 2023-08-0109:01:00 │ 11076 │ │ 2023-08-0109:02:00 │ 13705 │ │ 2023-08-0109:03:00 │ 12460 │ │ 2023-08-0109:04:00 │ 11379 │ │ 2023-08-0109:05:00 │ 13363 │ │ 2023-08-0109:06:00 │ 11438 │ … │ 2023-08-0109:54:00 │ 7972 │ │ 2023-08-0109:55:00 │ 8641 │ │ 2023-08-0109:56:00 │ 9696 │ │ 2023-08-0109:57:00 │ 8710 │ │ 2023-08-0109:58:00 │ 7495 │ │ 2023-08-0109:59:00 │ 7692 │ └─────────────────────┴───────┘ 60 rows inset. Elapsed:7.374 sec. Processed 42.97 million rows,2.20 GB (5.83 million rows/s.,298.59 MB/s.)Peak memory usage:66.99 MiB.
首届官方社区Meetup分享者火热招募中🔥🔥🔥
ClickHouse公司官方社区将于11月4日在北京举办首届ClickHouseBeijingUserGroupMeetup活动,面向社区招募本次技术沙龙活动的分享者。
云数据库 ClickHouse 版是阿里云提供的全托管 ClickHouse服务,是国内唯一和 ClickHouse 原厂达成战略合作并一方提供企业版内核服务的云产品。 企业版较社区版 ClickHouse 增强支持实时update&delete,云原生存算分离及Serverless 能力,整体成本可降低50%以上,现已开启邀测,欢迎申请体验(链接:https://www.aliyun.com/product/apsaradb/clickhouse)
产品介绍(https://www.aliyun.com/product/apsaradb/clickhouse)
技术交流群:
ClickHouse官方公众号: