perf(fields): create index for instance domain query (#9146)

# Which Problems Are Solved

get instance by domain cannot provide an instance id because it is not
known at that time. This causes a full table scan on the fields table
because current indexes always include the `instance_id` column.

# How the Problems Are Solved

Added a specific index for this query.

# Additional Context

If a system has many fields and there is no cache hit for the given
domain this query can heaviuly influence database CPU usage, the newly
added resolves this problem.
This commit is contained in:
Silvan 2025-01-07 17:06:33 +01:00 committed by GitHub
parent 11d36fcd00
commit f320d18b1a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 49 additions and 0 deletions

40
cmd/setup/43.go Normal file
View File

@ -0,0 +1,40 @@
package setup
import (
"context"
"embed"
"fmt"
"github.com/zitadel/logging"
"github.com/zitadel/zitadel/internal/database"
"github.com/zitadel/zitadel/internal/eventstore"
)
var (
//go:embed 43/cockroach/*.sql
//go:embed 43/postgres/*.sql
createFieldsDomainIndex embed.FS
)
type CreateFieldsDomainIndex struct {
dbClient *database.DB
}
func (mig *CreateFieldsDomainIndex) Execute(ctx context.Context, _ eventstore.Event) error {
statements, err := readStatements(createFieldsDomainIndex, "43", mig.dbClient.Type())
if err != nil {
return err
}
for _, stmt := range statements {
logging.WithFields("file", stmt.file, "migration", mig.String()).Info("execute statement")
if _, err := mig.dbClient.ExecContext(ctx, stmt.query); err != nil {
return fmt.Errorf("%s %s: %w", mig.String(), stmt.file, err)
}
}
return nil
}
func (mig *CreateFieldsDomainIndex) String() string {
return "43_create_fields_domain_index"
}

View File

@ -0,0 +1,3 @@
CREATE INDEX CONCURRENTLY IF NOT EXISTS fields_instance_domains_idx
ON eventstore.fields (object_id)
WHERE object_type = 'instance_domain' AND field_name = 'domain';

View File

@ -0,0 +1,3 @@
CREATE INDEX CONCURRENTLY IF NOT EXISTS fields_instance_domains_idx
ON eventstore.fields (object_id) INCLUDE (instance_id)
WHERE object_type = 'instance_domain' AND field_name = 'domain';

View File

@ -128,6 +128,7 @@ type Steps struct {
s38BackChannelLogoutNotificationStart *BackChannelLogoutNotificationStart s38BackChannelLogoutNotificationStart *BackChannelLogoutNotificationStart
s40InitPushFunc *InitPushFunc s40InitPushFunc *InitPushFunc
s42Apps7OIDCConfigsLoginVersion *Apps7OIDCConfigsLoginVersion s42Apps7OIDCConfigsLoginVersion *Apps7OIDCConfigsLoginVersion
s43CreateFieldsDomainIndex *CreateFieldsDomainIndex
} }
func MustNewSteps(v *viper.Viper) *Steps { func MustNewSteps(v *viper.Viper) *Steps {

View File

@ -171,6 +171,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
steps.s38BackChannelLogoutNotificationStart = &BackChannelLogoutNotificationStart{dbClient: esPusherDBClient, esClient: eventstoreClient} steps.s38BackChannelLogoutNotificationStart = &BackChannelLogoutNotificationStart{dbClient: esPusherDBClient, esClient: eventstoreClient}
steps.s40InitPushFunc = &InitPushFunc{dbClient: esPusherDBClient} steps.s40InitPushFunc = &InitPushFunc{dbClient: esPusherDBClient}
steps.s42Apps7OIDCConfigsLoginVersion = &Apps7OIDCConfigsLoginVersion{dbClient: esPusherDBClient} steps.s42Apps7OIDCConfigsLoginVersion = &Apps7OIDCConfigsLoginVersion{dbClient: esPusherDBClient}
steps.s43CreateFieldsDomainIndex = &CreateFieldsDomainIndex{dbClient: queryDBClient}
err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil) err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil)
logging.OnError(err).Fatal("unable to start projections") logging.OnError(err).Fatal("unable to start projections")
@ -242,6 +243,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string)
steps.s33SMSConfigs3TwilioAddVerifyServiceSid, steps.s33SMSConfigs3TwilioAddVerifyServiceSid,
steps.s37Apps7OIDConfigsBackChannelLogoutURI, steps.s37Apps7OIDConfigsBackChannelLogoutURI,
steps.s42Apps7OIDCConfigsLoginVersion, steps.s42Apps7OIDCConfigsLoginVersion,
steps.s43CreateFieldsDomainIndex,
} { } {
mustExecuteMigration(ctx, eventstoreClient, step, "migration failed") mustExecuteMigration(ctx, eventstoreClient, step, "migration failed")
} }