Heim >Backend-Entwicklung >Golang >Warum wird die Spanner-Abfrage mit ReadOnlyTransaction in Golang Goroutine allmählich langsamer?
Ich versuche, etwa 10.000 Zeilen aus einer Tabelle abzufragen. Nach dem Ausprobieren beteiligt limit
offset
的各种其他选项并且没有找到所需的成功之后,我尝试在每个 goroutine 中查询单行。思路是每行只需要 ~5ms
来查询和获取,但是一批 10k 会接管 20s
.
Unten ist eine vereinfachte Version des Codes dargestellt:
func queryEmp(IDs[]string, spannerClient *spanner.Client) (Employee,error){ query := "Select name from Employee Where id = @id" g, gCtx := errgroup.WithContext(ctx) for _, ID := range IDs { id := ID g.Go(func() error { tx := spannerClient.Single() defer tx.Close() stmt2 := spanner.NewStatement(query) stmt2.Params = map[string]interface{}{ "ID": id, } qstart := time.Now() it := tx.Query(gCtx, stmt2) defer it.Stop() logrus.Debugf("%s took %v \n", "query execution.", time.Since(qstart)) for { row, err := it.Next() if err == iterator.Done { break } if err != nil { return err } var eID string if err := row.Column(0, &eID); err != nil { return err } } return nil }) } err = g.Wait() }
Die Ergebnisse werden wie folgt verfolgt:
{"message":"query execution. took 39.677µs \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 34.125µs \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 26.634µs \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 29.303µs \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} ... ... ... {"message":"query execution. took 188.749562ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 276.424692ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 188.62849ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 217.067524ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 276.949166ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} ... ... ... {"message":"query execution. took 454.64281ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 452.0848ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 525.748738ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 454.704656ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} {"message":"query execution. took 455.4276ms \n","severity":"debug","time":"2023-11-03T20:51:29-04:00"} ... ... ... {"message":"query execution. took 6.767574136s \n","severity":"debug","time":"2023-11-03T20:52:00-04:00"} {"message":"query execution. took 6.780578444s \n","severity":"debug","time":"2023-11-03T20:52:00-04:00"} {"message":"query execution. took 6.785085491s \n","severity":"debug","time":"2023-11-03T20:52:00-04:00"} {"message":"query execution. took 6.779527006s \n","severity":"debug","time":"2023-11-03T20:52:00-04:00"}
Startet gut und wie erwartet, aber die Abfragezeiten nehmen immer mehr zu.
MaxSessions
和 MinSessions
对于 spannerClient
是 100
Man könnte sich also vorstellen, dass es nach 100 zu einer leichten Verlangsamung kommt, aber das ist nicht der Fall.
Bitte lesen Sie hier:
<code> Sessions can execute only one transaction at a time. Standalone reads, writes, and queries use a transaction internally, and count toward the one transaction limit. </code>
Nicht iterative Abfragen (ReadRow
usw.) liefern mir die gleichen Ergebnisse.
Die Verwendung von tx := spannerClient.Single()
außerhalb einer for-Schleife führt zu ähnlichen Ergebnissen.
Frage:
spannerClient.Single()
innerhalb der Goroutine immer noch versucht, dieselbe Sitzung/Transaktion zu verwenden? TLDR: Die standardmäßige maximale Sitzungspoolgröße beträgt 400, was bedeutet, dass Sie nie mehr als 400 Abfragen parallel ausführen können. Um diese Parallelität zu erreichen, müssen Sie die Größe des Sitzungspools erhöhen.
Zuallererst: Ich glaube nicht, dass das parallele Senden von 10.000 Abfragen, sodass jede Abfrage eine Zeile liest, nicht die effizienteste Lösung für Ihr Problem ist. Wenn Sie zum Filtern keine anderen Kriterien als die Mitarbeiter-IDs verwenden können und diese IDs überall verstreut sind, ist die Erstellung der Abfrage im Formular immer noch effizienter
select * from employees where id in unnest(@ids)
Ein vollständiges Beispiel finden Sie in diesem Kommentar: https:///github.com/googleapis/google-cloud-go/issues/858#issuecomment-550982307
Zurück zu Ihrer konkreten Frage:
it := tx.Query(gCtx, stmt2)
führt die Abfrage nicht aus, sondern bereitet sie lediglich auf die Ausführung vor. Wird ausgeführt, wenn row, err := it.Next()
zum ersten Mal aufgerufen wird. Dies können Sie auch an den erfassten Ausführungszeiten erkennen. Die erste Anweisung scheint innerhalb von 30 Mikrosekunden ausgeführt zu werden, was unmöglich ist. it := tx.Query(gCtx, stmt2)
行确实不执行查询,它只是准备执行查询。第一次调用 row, err := it.Next()
Das obige ist der detaillierte Inhalt vonWarum wird die Spanner-Abfrage mit ReadOnlyTransaction in Golang Goroutine allmählich langsamer?. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!