From 0d5d65e4c7859716d6a97723bae963ede246d476 Mon Sep 17 00:00:00 2001 From: Silvan <27845747+adlerhurst@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:06:33 +0100 Subject: [PATCH] perf(fields): create index for instance domain query (#9146) 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. Added a specific index for this query. 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. (cherry picked from commit f320d18b1a24b97b67500d471c11068fd09b6c39) --- cmd/setup/43.go | 40 +++++++++++++++++++++++++++++++++++ cmd/setup/43/cockroach/43.sql | 3 +++ cmd/setup/43/postgres/43.sql | 3 +++ cmd/setup/config.go | 1 + cmd/setup/setup.go | 2 ++ 5 files changed, 49 insertions(+) create mode 100644 cmd/setup/43.go create mode 100644 cmd/setup/43/cockroach/43.sql create mode 100644 cmd/setup/43/postgres/43.sql diff --git a/cmd/setup/43.go b/cmd/setup/43.go new file mode 100644 index 0000000000..844c25cf24 --- /dev/null +++ b/cmd/setup/43.go @@ -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" +} diff --git a/cmd/setup/43/cockroach/43.sql b/cmd/setup/43/cockroach/43.sql new file mode 100644 index 0000000000..9152130970 --- /dev/null +++ b/cmd/setup/43/cockroach/43.sql @@ -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'; \ No newline at end of file diff --git a/cmd/setup/43/postgres/43.sql b/cmd/setup/43/postgres/43.sql new file mode 100644 index 0000000000..2f6f958fdf --- /dev/null +++ b/cmd/setup/43/postgres/43.sql @@ -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'; \ No newline at end of file diff --git a/cmd/setup/config.go b/cmd/setup/config.go index ae62728c95..407a9412bb 100644 --- a/cmd/setup/config.go +++ b/cmd/setup/config.go @@ -128,6 +128,7 @@ type Steps struct { s38BackChannelLogoutNotificationStart *BackChannelLogoutNotificationStart s40InitPushFunc *InitPushFunc s42Apps7OIDCConfigsLoginVersion *Apps7OIDCConfigsLoginVersion + s43CreateFieldsDomainIndex *CreateFieldsDomainIndex } func MustNewSteps(v *viper.Viper) *Steps { diff --git a/cmd/setup/setup.go b/cmd/setup/setup.go index 497457ba8f..c803ab55b6 100644 --- a/cmd/setup/setup.go +++ b/cmd/setup/setup.go @@ -171,6 +171,7 @@ func Setup(ctx context.Context, config *Config, steps *Steps, masterKey string) steps.s38BackChannelLogoutNotificationStart = &BackChannelLogoutNotificationStart{dbClient: esPusherDBClient, esClient: eventstoreClient} steps.s40InitPushFunc = &InitPushFunc{dbClient: esPusherDBClient} steps.s42Apps7OIDCConfigsLoginVersion = &Apps7OIDCConfigsLoginVersion{dbClient: esPusherDBClient} + steps.s43CreateFieldsDomainIndex = &CreateFieldsDomainIndex{dbClient: queryDBClient} err = projection.Create(ctx, projectionDBClient, eventstoreClient, config.Projections, nil, nil, nil) 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.s37Apps7OIDConfigsBackChannelLogoutURI, steps.s42Apps7OIDCConfigsLoginVersion, + steps.s43CreateFieldsDomainIndex, } { mustExecuteMigration(ctx, eventstoreClient, step, "migration failed") }