Go Iterator 从 Bigquery 读取 100 万行,比 Java 或 kotlin 慢 10 倍?

Posted

技术标签:

【中文标题】Go Iterator 从 Bigquery 读取 100 万行,比 Java 或 kotlin 慢 10 倍?【英文标题】:Go Iterator reading 1 million rows from Bigquery 10x slower than Java or kotlin? 【发布时间】:2021-05-09 18:08:34 【问题描述】:

我的目的是使用 Go 查询 Biquery 并索引 Elasticsearch 中的一些字段。这将是一个一次性的批处理作业。由于团队拥有 Java 知识,我们决定对这两种语言进行基准测试。我注意到 Go 使用“迭代器方式”工作缓慢。

为什么会有这种时间差异?

我是否遗漏了 Go 中的某些客户端或查询配置,或者这是预期的行为?

如何提高阅读时间?

Java/kotlin 和 Go:

在完全相同的环境中运行。 Bigquery 数据集 200GB 相同的“sql”查询,连接两个表,只检索 12 个 ish 字段。限制 100 万行。 使用交互式查询从 GCP 文档中为两种语言运行示例代码:https://cloud.google.com/bigquery/docs/running-queries。

(我已经简化了代码)

转到 1.16.3

...

type Test struct 
    TestNo    *big.Rat              `bigquery:"testNo,nullable"`
    TestId    bigquery.NullString   `bigquery:"testId"`
    TestTime  bigquery.NullDateTime `bigquery:"testTime"`
    FirstName bigquery.NullString   `bigquery:"firstName"`
    LastName  bigquery.NullString   `bigquery:"lastName"`
    Items     []ItemTest            `bigquery:"f0_"`


type ItemTest struct 
    ItemType  bigquery.NullString `bigquery:"itemType"`
    ItemNo    bigquery.NullString `bigquery:"itemNo"`
    ProductNo *big.Rat            `bigquery:"productNo,nullable"`
    Qty       *big.Rat            `bigquery:"qty,nullable"`
    Name      bigquery.NullString `bigquery:"name"`
    Price     *big.Rat            `bigquery:"price,nullable"`



ctx := context.Background()
client, err := bigquery.NewClient(ctx, projectID)
if err != nil 
    // TODO: Handle error.



q := client.Query(myQuery)

it, err := q.Read(ctx)
if err != nil 
    // TODO: Handle error.



for 
    start := time.Now().UTC()

    var t Test
    err := it.Next(&t)
    if err == iterator.Done 
        break
    
    if err != nil 
        // TODO: Handle error.
    

    end += time.Since(start)

    IndexToES(t)
   


fmt.Println(end) //13 minutes.

...

读取和映射到 Go 结构需要 13 分钟

科特林

...

val start: BigDecimal = Instant.now().toEpochMilli().toBigDecimal().setScale(3)

val bigquery = BigQueryOptions.newBuilder()
            .setCredentials(credentials)
            .setProjectId(PROJECT_ID)
            .build()
            .service

val queryConfig = QueryJobConfiguration.newBuilder(query).build()

val tableResult = bigquery.query(queryConfig)

val test = results.iterateAll()
            .map  myMapper.mapToTest(it) 

val end: BigDecimal = Instant.now().toEpochMilli().toBigDecimal().setScale(3)


logResults(start, end) // 60000ms = 1minute 

fun logResults(start: BigDecimal, end: BigDecimal)
       println("query: " + (pitB - pitA).setScale(0) + "ms") 


//iterate through test and indexing at the same time
...

需要 1 分钟...

【问题讨论】:

请阅读:Can I ask only one question per post? 我不知道答案,因为我对go 知之甚少(更不用说它的内部结构),但它一定又是JVM 的奇妙表现方式 【参考方案1】:

sn-p 都不完整,所以不清楚这是否是苹果对苹果。如果您想知道 Go 程序的时间在哪里,请考虑利用 pprof。

要指出的另一件事是,如果您正在读取数百万行查询输出,您将需要查看BigQuery Storage API。使用它而不是您当前正在测试的迭代器可以使这两种语言的速度更快。

【讨论】:

以上是关于Go Iterator 从 Bigquery 读取 100 万行,比 Java 或 kotlin 慢 10 倍?的主要内容,如果未能解决你的问题,请参考以下文章

从 Google Cloud BigQuery 读取数据

如何从 BigQuery 作为流读取

如何从 Dataflow 中的 PCollection 读取 bigQuery

Cloud Dataflow 中的“辅助输入”是不是支持从 BigQuery 视图中读取?

Bigquery 命令行工具,用于从文件中读取长查询字符串

从 BigQuery 读取数据并将其写入云存储上的 avro 文件格式