优先选http接口,因其稳定、易调试、兼容性好且性能接近tcp;tcp仅适用于高频低延迟写入等极少数场景。

ClickHouse PHP连接选HTTP还是TCP?先看你的部署环境
HTTP接口是官方推荐的默认方式,适合绝大多数PHP应用;TCP驱动(如 clickhouse-client 或第三方 php-clickhouse 扩展)只在极少数场景下有优势——比如你已用C扩展做高频低延迟写入,且能接受编译依赖和维护成本。绝大多数Web后台、ETL脚本、报表服务,直接走HTTP更稳、更易调试、兼容性更好。
- HTTP基于REST,PHP原生
curl或guzzlehttp/guzzle就能发请求,无需额外扩展 - TCP驱动(如
php-clickhouse的ext-clickhouse)需要编译安装,PHP 8.2+ 兼容性差,文档少,出错时堆栈难追踪 - ClickHouse官方明确标注:HTTP接口性能已优化到接近原生协议,95%以上查询场景无感知差异
用cURL发HTTP请求连ClickHouse,绕不开的三个配置点
ClickHouse的HTTP接口默认监听 8123 端口,但很多新手卡在认证、格式、超时上,不是连不上,就是返回空或401。
- 必须显式设置
Content-Type: application/x-www-form-urlencoded,否则即使SQL语法正确,ClickHouse也可能静默忽略请求体 - 认证凭据不能放URL里(如
@#@#@#@#@#@#@#@#@#@0),部分版本会丢掉密码;应改用Authorization: Basic头,或在POST body中传user和password参数 - 查询超时要设够:
curl_setopt($ch, CURLOPT_TIMEOUT, 30),大数据量GROUP BY或JOIN很容易跑过10秒,不设容易被PHP或Nginx中途掐断
$ch = curl_init('http://localhost:8123/');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => 'SELECT count() FROM system.tables',
CURLOPT_HTTPHEADER => ['Content-Type: application/x-www-form-urlencoded'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 30,
]);
$result = curl_exec($ch);
用Guzzle发带参数的ClickHouse查询,注意query string和body的分工
Guzzle更简洁,但容易混淆哪儿该放SQL、哪儿该放配置参数。ClickHouse HTTP接口把「查询语句」当body,把「格式控制」「用户凭证」「压缩开关」等当URL query参数。
- SQL必须放在
body,不能塞进query;否则会被当成无效参数忽略 -
database、default_format、enable_http_compression这类控制项,必须拼在URL里,例如?database=default&default_format=JSONEachRow - 如果启用了
output_format_json_quote_64bit_integers=0,整数不会被引号包裹,PHPjson_decode()才能正确转成int而非string
$client = new \GuzzleHttp\Client();
$response = $client->post('http://localhost:8123/?database=default&default_format=JSONEachRow', [
'body' => 'SELECT * FROM visits WHERE date >= today() - 7 LIMIT 10',
'headers' => ['Authorization' => 'Basic ' . base64_encode('default:')],
]);
为什么你查出来的时间字段是字符串而不是DateTime?
ClickHouse的 Date 和 DateTime 类型,在HTTP响应中默认序列化为字符串(如 "2024-05-20" 或 "2024-05-20 14:23:11"),PHP不会自动转成 DateTime 对象。这不是Bug,是设计使然——HTTP协议本身没有类型系统。
- 不要指望
json_decode($body, true)后直接拿$row['event_time']->format(...),它就是个string - 若需转换,得自己用
new DateTime($row['event_time']),注意时区:ClickHouse存的是UTC,而PHP默认用本地时区解析,建议显式指定new DateTime($row['event_time'], new DateTimeZone('UTC')) - 更稳妥的做法是在SQL里用
toString(event_time)或toUnixTimestamp(event_time)提前格式化,避免PHP层处理歧义
真正麻烦的不是连不上,而是连上了却对数据类型“视而不见”——尤其当字段名含 time、date 时,人眼容易误判它已是对象。
php免费学习视频:立即使用
踏上前端学习之旅,开启通往精通之路!从前端基础到项目实战,循序渐进,一步一个脚印,迈向巅峰!











