From f320d18b1a24b97b67500d471c11068fd09b6c39 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) # 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. --- 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") }