我正在尝试执行查询(带有10个字段的Basic select语句)。我的表包含超过500k行。 C#应用程序仅返回4260行的响应。但Web UI会返回所有记录。
为什么我的代码只返回部分数据,选择所有记录并加载到C#数据表的最佳方法是什么?如果有任何代码段,对我来说会更有帮助。
using Google.Apis.Auth.OAuth2;
using System.IO;
using System.Threading;
using Google.Apis.Bigquery.v2;
using Google.Apis.Bigquery.v2.Data;
using System.Data;
using Google.Apis.Services;
using System;
using System.Security.Cryptography.X509Certificates;
namespace GoogleBigQuery
{
public class Class1
{
private static void Main()
{
try
{
Console.WriteLine("Start Time: {0}", DateTime.Now.ToString());
String serviceAccountEmail = "SERVICE ACCOUNT EMAIL";
var certificate = new X509Certificate2(@"KeyFile.p12", "notasecret", X509KeyStorageFlags.Exportable);
ServiceAccountCredential credential = new ServiceAccountCredential(
new ServiceAccountCredential.Initializer(serviceAccountEmail)
{
Scopes = new[] { BigqueryService.Scope.Bigquery, BigqueryService.Scope.BigqueryInsertdata, BigqueryService.Scope.CloudPlatform, BigqueryService.Scope.DevstorageFullControl }
}.FromCertificate(certificate));
BigqueryService Service = new BigqueryService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = "PROJECT NAME"
});
string query = "SELECT * FROM [publicdata:samples.shakespeare]";
JobsResource j = Service.Jobs;
QueryRequest qr = new QueryRequest();
string ProjectID = "PROJECT ID";
qr.Query = query;
qr.MaxResults = Int32.MaxValue;
qr.TimeoutMs = Int32.MaxValue;
DataTable DT = new DataTable();
int i = 0;
QueryResponse response = j.Query(qr, ProjectID).Execute();
string pageToken = null;
if (response.JobComplete == true)
{
if (response != null)
{
int colCount = response.Schema.Fields.Count;
if (DT == null)
DT = new DataTable();
if (DT.Columns.Count == 0)
{
foreach (var Column in response.Schema.Fields)
{
DT.Columns.Add(Column.Name);
}
}
pageToken = response.PageToken;
if (response.Rows != null)
{
foreach (TableRow row in response.Rows)
{
DataRow dr = DT.NewRow();
for (i = 0; i < colCount; i++)
{
dr[i] = row.F[i].V;
}
DT.Rows.Add(dr);
}
}
Console.WriteLine("No of Records are Readed: {0} @ {1}", DT.Rows.Count.ToString(), DateTime.Now.ToString());
while (true)
{
int StartIndexForQuery = DT.Rows.Count;
Google.Apis.Bigquery.v2.JobsResource.GetQueryResultsRequest SubQR = Service.Jobs.GetQueryResults(response.JobReference.ProjectId, response.JobReference.JobId);
SubQR.StartIndex = (ulong)StartIndexForQuery;
//SubQR.MaxResults = Int32.MaxValue;
GetQueryResultsResponse QueryResultResponse = SubQR.Execute();
if (QueryResultResponse != null)
{
if (QueryResultResponse.Rows != null)
{
foreach (TableRow row in QueryResultResponse.Rows)
{
DataRow dr = DT.NewRow();
for (i = 0; i < colCount; i++)
{
dr[i] = row.F[i].V;
}
DT.Rows.Add(dr);
}
}
Console.WriteLine("No of Records are Readed: {0} @ {1}", DT.Rows.Count.ToString(), DateTime.Now.ToString());
if (null == QueryResultResponse.PageToken)
{
break;
}
}
else
{
break;
}
}
}
else
{
Console.WriteLine("Response is null");
}
}
int TotalCount = 0;
if (DT != null && DT.Rows.Count > 0)
{
TotalCount = DT.Rows.Count;
}
else
{
TotalCount = 0;
}
Console.WriteLine("End Time: {0}", DateTime.Now.ToString());
Console.WriteLine("No. of records readed from google bigquery service: " + TotalCount.ToString());
}
catch (Exception e)
{
Console.WriteLine("Error Occurred: " + e.Message);
}
Console.ReadLine();
}
}
}
在此示例查询中获取公共数据集的结果,In表中包含164656行,但响应仅首次返回85000行,然后再次查询以获取第二组结果。 (但不知道这是获得所有结果的唯一解决方案。)
在这个示例中只包含4个字段,即使它不返回所有行,在我的case表中包含超过15个字段,我得到约~10k行~~ 4000行的响应,我需要再次查询再次获取选择1000行的剩余结果需要时间长达2分钟,因此我期望在单个响应中选择所有记录的最佳方式。
答案 0 :(得分:2)
来自用户#的答案:Pentium10
无法运行查询并在单次拍摄中选择较大的响应。您可以对结果进行分页,也可以创建要导出到文件的作业,然后使用应用程序中生成的文件。出口是免费的。
步骤运行大型查询并将结果导出到存储在GCS上的文件:
1)在作业配置中将allowLargeResults设置为true。您还必须使用allowLargeResults标志指定目标表。
示例:强>
"configuration":
{
"query":
{
"allowLargeResults": true,
"query": "select uid from [project:dataset.table]"
"destinationTable": [project:dataset.table]
}
}
2)现在您的数据位于您设置的目标表中。您需要创建一个新作业,并将导出属性设置为能够将表导出到文件。导出是免费的,但您需要激活Google云端存储才能将结果文件放在那里。
3)最后,您从GCS下载大文件。
轮到我设计解决方案以获得更好的结果。
答案 1 :(得分:0)
Web UI自动flattens数据。这意味着您会看到每个嵌套字段有多行。
当您通过API运行相同的查询时,它将不会被展平,并且您将获得更少的行,因为嵌套字段作为对象返回。您应该检查是否属于这种情况。
另一个是你确实需要对结果进行分页。 Paging through list results解释了这一点。
如果您只想做一个工作,而不是将查询输出写入表,而不是将表导出为JSON,并从GCS下载导出。
答案 2 :(得分:0)
希望这可以帮助某人。可以使用PageToken检索下一组分页结果。以下是如何使用PageToken的示例代码。虽然,我喜欢免费出口的想法。在这里,我将行写入平面文件,但您可以将它们添加到DataTable中。显然,将大型DataTable保留在内存中是一个坏主意。
public void ExecuteSQL(BigqueryService bqservice, String ProjectID)
{
string sSql = "SELECT r.Dealname, r.poolnumber, r.loanid FROM [MBS_Dataset.tblRemitData] R left join each [MBS_Dataset.tblOrigData] o on R.Dealname = o.Dealname and R.Poolnumber = o.Poolnumber and R.LoanID = o.LoanID Order by o.Dealname, o.poolnumber, o.loanid limit 100000";
QueryRequest _r = new QueryRequest();
_r.Query = sSql;
QueryResponse _qr = bqservice.Jobs.Query(_r, ProjectID).Execute();
string pageToken = null;
if (_qr.JobComplete != true)
{
//job not finished yet! expecting more data
while (true)
{
var resultReq = bqservice.Jobs.GetQueryResults(_qr.JobReference.ProjectId, _qr.JobReference.JobId);
resultReq.PageToken = pageToken;
var result = resultReq.Execute();
if (result.JobComplete == true)
{
WriteRows(result.Rows, result.Schema.Fields);
pageToken = result.PageToken;
if (pageToken == null)
break;
}
}
}
else
{
List<string> _fieldNames = _qr.Schema.Fields.ToList().Select(x => x.Name).ToList();
WriteRows(_qr.Rows, _qr.Schema.Fields);
}
}