我们的任务是在ClickHouse中运行一批~20000个查询,并将结果存储到CSV文件中。每个查询都是一个count()聚合,返回一个数字。
我们这样做:
./generate_queries.js | clickhouse-client --multiquery | tr '\n' ',' >> metrics.csv
(是的,尾随逗号,我们会解决这个问题。)
查询示例:
SELECT count(*) FROM merged_data WHERE business_type = 22;
问题是如果查询匹配零记录,ClickHouse只返回任何内容,结果CSV文件中的记录数与查询数不同。
这可能是SQL的标准行为,但我们如何解决这个问题并使ClickHouse count()在零匹配的情况下返回0?
答案 0 :(得分:2)
现在你可以这样做:
SELECT
count() - 1
FROM (
SELECT
business_type
FROM
merged_data
WHERE
business_type = 22
UNION ALL
toUInt64(1)
)
只需将toUInt64
替换为business_type
的任何类型。
开发人员已经意识到了这个问题并且正在努力解决这个问题: https://github.com/yandex/ClickHouse/issues/51 https://groups.google.com/forum/#!topic/clickhouse/2JS_yzvYAHM
目前的计划是添加一种从设置中控制此行为的功能。
答案 1 :(得分:1)
我们设法使用JSON输出格式来解决这个问题。
SELECT count(*) FROM merged_data WHERE business_type = 22 FORMAT JSONCompact;
这种情况下的数据库响应如下:
{
"meta":
[
{
"name": "count()",
"type": "UInt64"
}
],
"data":
[
],
"rows": 0,
"statistics":
{
"elapsed": 0.044646461,
"rows_read": 53413865,
"bytes_read": 53413865
}
}
即使是空匹配,总会有回复(如果是这种情况,我们会看到"rows": 0
。)
JSON响应流解析器如下所示:
var readLine = require('readline');
var rl = readLine.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
var buf = '';
rl.on('line', line => {
buf += line;
if (line == '}') {
// End of JSON => process.
var json = JSON.parse(buf);
buf = '';
if (json.rows === 0) {
console.log('0');
}
else {
console.log(json.data[0][0]);
}
}
});
答案 2 :(得分:0)
这是ClickHouse的已知问题。 要解决此问题,请按照以下步骤操作。
假设你的计数查询是这样的:
SELECT count(*) AS count
FROM mytable
将您的查询放入此sql模板:
SELECT *
FROM
(
-- put your cunt query here
UNION ALL
SELECT toUInt64(0)
)
LIMIT 1
所以最终的查询将是:
SELECT *
FROM
(
SELECT count(*) AS count
FROM mytable
UNION ALL
SELECT toUInt64 (0)
)
LIMIT 1
注意:使用此解决方法没有性能开销。