simpod / clickhouse-client
PHP ClickHouse客户端
Requires
- php: ^8.2
- guzzlehttp/promises: ^2.0
- guzzlehttp/psr7: ^2.6
- php-http/client-common: ^2.0
- psr/http-client: ^1.0
- psr/http-factory: ^1.0
- psr/http-message: ^2.0
- psr/log: ^3
Requires (Dev)
- cdn77/coding-standard: ^7.0
- infection/infection: ^0.28.0
- nyholm/psr7: ^1.2
- php-http/message-factory: ^1.1
- phpstan/extension-installer: ^1.1
- phpstan/phpstan: ^1.0.0
- phpstan/phpstan-phpunit: ^1.0.0
- phpstan/phpstan-strict-rules: ^1.0.0
- phpunit/phpunit: ^11.0
- symfony/http-client: ^7.0
README
动机
该库尽量不隐藏任何ClickHouse HTTP接口的特定细节。也就是说,一切都是尽可能透明的,并且提供了面向对象的API,而不发明自己的抽象。
这里使用的命名与ClickHouse文档中的相同。
- 与任何HTTP客户端实现(符合PSR-18)兼容
- 支持所有ClickHouse格式
- 日志(符合PSR-3)
- SQL工厂用于参数“绑定”
- 支持原生查询参数
内容
设置
composer require simpod/clickhouse-client
- 阅读有关ClickHouse Http接口 的内容。 它很短,但有助于理解概念。
- 创建一个新的ClickHouse客户端实例,并传递PSR工厂。
- 建议使用Symfony HttpClient(性能,更少错误,维护)
- 这个转折点是,这个库中没有配置端点/凭据等,而是通过客户端提供。
- 查看测试
<?php use Http\Client\Curl\Client; use Nyholm\Psr7\Factory\Psr17Factory; use SimPod\ClickHouseClient\Client\PsrClickHouseClient; use SimPod\ClickHouseClient\Client\Http\RequestFactory; $psr17Factory = new Psr17Factory; $clickHouseClient = new PsrClickHouseClient( new Client(), new RequestFactory( $psr17Factory, $psr17Factory ), [], new DateTimeZone('UTC') );
Symfony HttpClient示例
配置HTTP客户端
如ClickHouse HTTP接口规范中所述,我们使用头部进行认证,例如通过查询设置默认数据库。
framework: http_client: scoped_clients: click_house.client: base_uri: '%clickhouse.endpoint%' headers: 'X-ClickHouse-User': '%clickhouse.username%' 'X-ClickHouse-Key': '%clickhouse.password%' query: database: '%clickhouse.database%'
日志
SimPod\ClickHouseClient\Client\Http\LoggerPlugin
可与 HTTPlug PluginClient 一起使用。
这是
<?php declare(strict_types=1); namespace Cdn77\Mon\Core\Infrastructure\Symfony\Service\ClickHouse; use Http\Client\Common\PluginClient; use SimPod\ClickHouseClient\Client\Http\LoggerPlugin; use SimPod\ClickHouseClient\Logger\SqlLogger; use Symfony\Component\HttpClient\HttplugClient; use Symfony\Contracts\HttpClient\HttpClientInterface; final class HttpClientFactory { public function __construct(private HttpClientInterface $clickHouseClient, private SqlLogger $sqlLogger) { } public function create() : PluginClient { return new PluginClient( new HttplugClient($this->clickHouseClient), [new LoggerPlugin($this->sqlLogger)] ); } }
时区
ClickHouse没有带时区的日期时间。因此,您需要规范化作为参数传递的日期时间的时区,以确保适当的输入格式。
以下将作为 2020-01-31 01:00:00
插入到ClickHouse中。
new DateTimeImmutable('2020-01-31 01:00:00', new DateTimeZone('Europe/Prague'));
如果您的服务器使用 UTC
,则该值对您不正确,实际上您需要插入 2020-01-31 00:00:00
。
通过将 DateTimeZone
传递到 PsrClickHouseClient
构造函数中,启用时区规范化。
new PsrClickHouseClient(..., new DateTimeZone('UTC'));
PSR工厂是?
该库没有实现自己的HTTP。这已经通过 PSR-7, PSR-17 和 PSR-18 完成。该库遵守它,并允许您插入自己的实现(例如HTTPPlug或Guzzle)。
建议使用 composer require nyholm/psr7
用于PSR-17,并使用 composer require php-http/curl-client
用于Curl PSR-18实现(如上例所示)。
同步API
选择
ClickHouseClient::select()
用于 SELECT
和 SHOW
查询。将 FORMAT
添加到查询中,并以所选输出格式返回响应
<?php use SimPod\ClickHouseClient\Client\ClickHouseClient; use SimPod\ClickHouseClient\Format\JsonEachRow; use SimPod\ClickHouseClient\Output; /** @var ClickHouseClient $client */ /** @var Output\JsonEachRow $output */ $output = $client->select( 'SELECT * FROM table', new JsonEachRow(), ['force_primary_key' => 1] );
选择带参数
ClickHouseClient::selectWithParams()
与 ClickHouseClient::select()
相同,但还允许 参数绑定。
<?php use SimPod\ClickHouseClient\Client\ClickHouseClient; use SimPod\ClickHouseClient\Format\JsonEachRow; use SimPod\ClickHouseClient\Output; /** @var ClickHouseClient $client */ /** @var Output\JsonEachRow $output */ $output = $client->selectWithParams( 'SELECT * FROM :table', ['table' => 'table_name'], new JsonEachRow(), ['force_primary_key' => 1] );
插入
ClickHouseClient::insert()
<?php use SimPod\ClickHouseClient\Client\ClickHouseClient; /** @var ClickHouseClient $client */ $client->insert('table', $data, $columnNames);
如果提供了 $columnNames
并且是键-值数组,则根据它生成列名,并将值作为参数传递
$client->insert('table', [[1,2]], ['a' => 'Int8', 'b' => 'String']);
生成 INSERT INTO table (a,b) VALUES ({p1:Int8},{p2:String})
并将值传递给查询。
如果提供了 $columnNames
,则根据它生成列名。
$client->insert('table', [[1,2]], ['a', 'b']);
生成 INSERT INTO table (a,b) VALUES (1,2)
。
如果省略了 $columnNames
,则从 $data
读取列名。
$client->insert('table', [['a' => 1,'b' => 2]]);
生成 INSERT INTO table (a,b) VALUES (1,2)
。
列名只从第一个项目读取。
$client->insert('table', [['a' => 1,'b' => 2], ['c' => 3,'d' => 4]]);
生成 INSERT INTO table (a,b) VALUES (1,2),(3,4)
。
如果没有提供,它们也不会传递。
$client->insert('table', [[1,2]]);
生成 INSERT INTO table VALUES (1,2)
。
异步API
选择
参数 "绑定"。
<?php use SimPod\ClickHouseClient\Sql\SqlFactory; use SimPod\ClickHouseClient\Sql\ValueFormatter; $sqlFactory = new SqlFactory(new ValueFormatter()); $sql = $sqlFactory->createWithParameters( 'SELECT :param', ['param' => 'value'] );
这会产生 SELECT 'value'
并可以传递给 ClickHouseClient::select()
。
支持的类型有
- 标量
- DateTimeImmutable(《\DateTime》不受支持,因为《ValueFormatter》可能会修改它的时区,所以它不被认为是安全的)
- 表达式
- 实现
__toString()
的对象
原生查询参数
提示
<?php use SimPod\ClickHouseClient\Client\PsrClickHouseClient; $client = new PsrClickHouseClient(...); $output = $client->selectWithParams( 'SELECT {p1:String}', ['param' => 'value'] );
所有类型都受支持(设计上除外 AggregateFunction
,SimpleAggregateFunction
和 Nothing
)。您还可以将 DateTimeInterface
传递到 Date*
类型或将本地数组传递到 Array
,Tuple
,Native
和 Geo
类型
表达式
为了表示复杂表达式,存在 SimPod\ClickHouseClient\Sql\Expression
类。当传递给 SqlFactory
时,其值将被评估。
要将例如 UUIDStringToNum('6d38d288-5b13-4714-b6e4-faa59ffd49d8')
传递到 SQL
<?php use SimPod\ClickHouseClient\Sql\Expression; Expression::new("UUIDStringToNum('6d38d288-5b13-4714-b6e4-faa59ffd49d8')");
<?php use SimPod\ClickHouseClient\Sql\ExpressionFactory; use SimPod\ClickHouseClient\Sql\ValueFormatter; $expressionFactory = new ExpressionFactory(new ValueFormatter()); $expression = $expressionFactory->templateAndValues( 'UUIDStringToNum(%s)', '6d38d288-5b13-4714-b6e4-faa59ffd49d8' );
代码片段
有一些方便的查询,例如获取数据库大小、表列表、当前数据库等。
为了防止客户端 API 污染,这些被提取到代码片段中。
获取当前数据库名的示例
<?php use SimPod\ClickHouseClient\Snippet\CurrentDatabase; $currentDatabaseName = CurrentDatabase::run($client);
列表
- 当前数据库
- 数据库大小
- 部分
- 显示创建表
- 显示数据库
- 表大小
- 版本