我正在使用Google BigQuery,并从PHP执行一些简单的查询。(例如,从电子邮件中选择*,其中电子邮件='mail@test.com’)我只是在检查表中是否存在电子邮件。
"电子邮件"表目前为空。但是PHP脚本仍然需要大约4分钟来检查空表上的175封电子邮件。。正如我所希望的那样,未来表格将被填满,并将有50万封邮件,那么我想请求时间会更长。
这正常吗?或者有什么想法/解决方案可以改善检查时间?
(附言:"电子邮件"表仅包含8列,均为字符串类型)
谢谢!
如果您只是检查字段的存在,请考虑使用SELECT COUNT(*) FROM emails where email='mail@test.com'
。这只需要读取一个字段,因此在大型表上成本更低,速度略快。
正如Pentium10所建议的,考虑在一个查询中使用多个查找。你可以这样做:
SELECT SUM((IF(email = 'mail1@test.com', 1, 0)) as m1,
SUM((IF(email = 'mail2@test.com', 1, 0)) as m2,
SUM((IF(email = 'mail3@test.com', 1, 0)) as m3,
...
FROM emails
在一个查询中,您将被限制为64k个这样的值,但它的计算速度应该非常快,因为它只需要在一次扫描中扫描一列
或者,如果你想让电子邮件每行一封,你可以做一些更花哨的事情,比如
SELECT email FROM emails WHERE email IN
('mail1@test.com', 'mail2@test.com', 'mail3@test.com'...)
GROUP BY email
作为进一步的优化,您可以将其作为LEFT JOIN:
SELECT t1.email as email, IF(t2.email is not null, true, false) as found
FROM [interesting_emails] t1
LEFT OUTER JOIN [emails] t2 ON t1.email = t2.email
如果有趣的电子邮件中有你想查看的电子邮件列表,比如
mail1@test.com
mail2@test.com
mail3@test.com
如果电子邮件表只包含mail1@和mail2@,那么你会得到结果:
email found
______________ _____
mail1@test.com true
mail2@test.com false
mail3@test.com true
这样做的好处是,如果需要,它可以扩展到数十亿封电子邮件(当数量变大时,您可能会考虑使用JOIN EACH而不是JOIN)。
下面是一个用PHP进行流式插入的示例代码,使用https://github.com/google/google-api-php-client:
/**
*
* @param type $client
* @param type $project_id
* @param type $dataset_id
* @param type $rows
* @return boolean
* @throws Google_Service_Exception
*/
public function BQ_Tabledata_InsertAll($client, $project_id, $dataset_id, $rows) {
$bq = new Google_Service_Bigquery($client);
$request = new Google_Service_Bigquery_TableDataInsertAllRequest();
$request->setRows($rows);
try {
$resp = new Google_Service_Bigquery_TableDataInsertAllResponse();
$resp = $bq->tabledata->insertAll($project_id, $dataset_id, static::tableId(), $request);
$errors = new Google_Service_Bigquery_TableDataInsertAllResponseInsertErrors();
$errors = @$resp->getInsertErrors();
if (!empty($errors)) {
$error_msg = '';
if (is_array($errors)) {
$line = 0;
foreach ($errors as $eP) {
$arr = $eP->getErrors();
if (is_array($arr)) {
foreach ($arr as $e) {
switch ($e->getReason()) {
case "stopped":
break;
default:
$error_msg.= sprintf("Error on line %s: %s'r'n", $line, $e->getMessage());
break;
}
}
}
$line++;
}
$this->setErrorMessage($error_msg);
} else {
$this->setErrorMessage($errors);
}
//print_r($errors);
//exit;
return false;
}
return true;
} catch (Google_Service_Exception $e) {
$this->setErrors($e->getErrors())->setErrorMessage($e->getMessage());
throw $e;
}
}