BigQuery查询中条件语句及LIMIT均被忽略,返回全表数据是什么原因?
问题描述
我有一个包含多列的BigQuery表,其中一列名为my_id,数据类型为STRING,我用以下代码查询BigQuery数据集:
import * as bq from "@google-cloud/bigquery"; const bqdb = new bq.BigQuery(); // ... const projectId = 'my_project'; const datasetId = "my_dataset"; const tableId = "my_table"; const dbId = [projectId, datasetId, tableId].join('.'); // myIds是字符串数组 const stringedArray = myIds.map((id) => '\'' + id + '\''); const sql_select_query = ` SELECT my_id FROM \`${dbId}\` WHERE my_id IN (${String(stringedArray)}) LIMIT 1 ; `; const dataset = bqdb.dataset(datasetId); const destinationTable = dataset.table(tableId); console.log("Querying database..."); const queryOptions = { query: sql_select_query, destination: destinationTable, write_disposition: "WRITE_APPEND", priority: 'BATCH', }; // 以作业形式运行查询 const [job] = await bqdb.createQueryJob(queryOptions); // 等待作业执行完成 const results = await job.getQueryResults({maxResults: 500}); const resutsArray = results[0]
查询返回了整张表的所有行和所有列,和执行以下语句的结果完全一致:
const sql_select_query = ` SELECT * FROM \`${dbId}\` ; `;
查询执行成功,没有任何错误或警告,但WHERE条件、LIMIT限制都完全失效了,请问为什么BigQuery会返回整张表的数据?
原因分析
核心问题出在查询配置的destination参数上:你将本次查询的结果写入目标表设置成了本次查询的源表本身,配合write_disposition: "WRITE_APPEND"的配置,触发了BigQuery客户端的默认行为:
你写的SELECT、WHERE、LIMIT实际上都正常执行了,只是当你为查询明确指定了持久化的目标写入表时,BigQuery不会将查询结果保存在临时结果集中,而是直接写入你指定的目标表。此时Node.js版BigQuery客户端的getQueryResults()方法默认会拉取整个目标表的全量数据,而非仅返回本次查询得到的结果集,所以你看到的是整张源表的所有内容,看起来就像条件和限制都失效了一样。
额外注意:你目前的配置会把每次查询得到的符合条件的行追加到源表中,长期运行会导致源表数据重复膨胀,还可能出现列不匹配的潜在错误。
解决方案
- 如果你不需要持久化保存查询结果,直接删除
queryOptions里的destination和write_disposition配置即可,此时getQueryResults()会直接返回本次查询的结果,符合你的预期。 - 如果你确实需要将查询结果持久化写入表,换一个和源表不同的表作为写入目标,避免数据污染。如果需要同时拿到本次查询的结果,可以先不指定
destination拿到查询结果后,再自行写入目标表。
内容的提问来源于stack exchange,提问作者zakdances
相关产品推荐
相关产品推荐

