2016-08-11 3 views
3

Я создаю утилиту, которая должна быть осведомлена обо всех наборах данных/таблицах, которые существуют в моем проекте BigQuery. Мой текущий код для получения этой информации следующим образом (с помощью Go API):Нужно ускорить отправку всех наборов данных/таблиц в проекте

func populateExistingTableMap(service *bigquery.Service, cloudCtx context.Context, projectId string) (map[string]map[string]bool, error) { 
    tableMap := map[string]map[string]bool{} 

    call := service.Datasets.List(projectId) 
    //call.Fields("datasets/datasetReference") 

    if err := call.Pages(cloudCtx, func(page *bigquery.DatasetList) error { 
     for _, v := range page.Datasets { 

      if tableMap[v.DatasetReference.DatasetId] == nil { 
       tableMap[v.DatasetReference.DatasetId] = map[string]bool{} 
      } 

      table_call := service.Tables.List(projectId, v.DatasetReference.DatasetId) 
      //table_call.Fields("tables/tableReference") 

      if err := table_call.Pages(cloudCtx, func(page *bigquery.TableList) error { 
       for _, t := range page.Tables { 
        tableMap[v.DatasetReference.DatasetId][t.TableReference.TableId] = true 
       } 
       return nil 
      }); err != nil { 
       return errors.New("Error Parsing Table") 
      } 
     } 
     return nil 
    }); err != nil { 
     return tableMap, err 
    } 

    return tableMap, nil 
} 

Для проекта с около 5000 наборов данных, каждый из которых до 10 столов, этот код занимает почти 15 минут, чтобы вернуться. Есть ли более быстрый способ перебора имен всех существующих наборов данных/таблиц? Я попытался использовать метод Fields, чтобы возвращать только те поля, которые мне нужны (вы можете видеть эти строки, отмеченные выше), но это приводит к тому, что возвращается только 50 (ровно 50) моих наборов данных.

Любые идеи?

+3

Кажется, что этого не хватает параллелизма. После того, как вы получите исходные данные datasets.list, вы можете обрабатывать базы данных самостоятельно. – shollyman

+0

@shollyman хороший звонок, смог получить его в среднем на 3 минуты с параллелизмом. –

+1

можете ли вы использовать код в качестве ответа? –

ответ

2

Вот обновленная версия моего кода с параллелизмом, которая сократила время обработки от 15 минут до 3 минут.

func populateExistingTableMap(service *bigquery.Service, cloudCtx context.Context, projectId string) (map[string]map[string]bool, error) { 
    tableMap = map[string]map[string]bool{} 

    call := service.Datasets.List(projectId) 
    //call.Fields("datasets/datasetReference") 

    if err := call.Pages(cloudCtx, func(page *bigquery.DatasetList) error { 
     var wg sync.WaitGroup 
     wg.Add(len(page.Datasets)) 
     for _, v := range page.Datasets { 
      if tableMap[v.DatasetReference.DatasetId] == nil { 
       tableMap[v.DatasetReference.DatasetId] = map[string]bool{} 
      } 

      go func(service *bigquery.Service, datasetID string, projectId string) { 
       defer wg.Done() 
       table_call := service.Tables.List(projectId, datasetID) 
       //table_call.Fields("tables/tableReference") 
       if err := table_call.Pages(cloudCtx, func(page *bigquery.TableList) error { 
        for _, t := range page.Tables { 
         tableMap[datasetID][t.TableReference.TableId] = true 
        } 
        return nil // NOTE: returning a non-nil error stops pagination. 
       }); err != nil { 
        // TODO: Handle error. 
        fmt.Println(err) 
       } 
      }(service, v.DatasetReference.DatasetId, projectId) 
     } 

     wg.Wait() 
     return nil // NOTE: returning a non-nil error stops pagination. 
    }); err != nil { 
     return tableMap, err 
     // TODO: Handle error. 
    } 

    return tableMap, nil 
} 
+1

приятно. Я пробовал аналогичный подход вчера, но с каналами и видел подобное улучшение производительности. –

Смежные вопросы