From fa4bc43aa0e925f2d4a2d4c16949b0a8052f09af Mon Sep 17 00:00:00 2001
From: Dzmitry Meshcharakou <12459192-dmeshcharakou@users.noreply.gitlab.com>
Date: Mon, 3 Jun 2024 14:50:28 +0000
Subject: [PATCH] Add index to package files on package_id, status and file
 extension

Adding the index to package files table on package_id, status and file
extension will improve the perfomance of NuGet metadata endpoints and
can be used instead of existing GIN index.

Changelog: performance
---
 app/models/packages/package_file.rb           |  2 +-
 ...extension_status_index_to_package_files.rb | 19 +++++++++++++++++++
 db/schema_migrations/20240523145415           |  1 +
 db/structure.sql                              |  2 ++
 spec/models/packages/package_file_spec.rb     |  2 +-
 5 files changed, 24 insertions(+), 2 deletions(-)
 create mode 100644 db/post_migrate/20240523145415_add_package_id_file_extension_status_index_to_package_files.rb
 create mode 100644 db/schema_migrations/20240523145415

diff --git a/app/models/packages/package_file.rb b/app/models/packages/package_file.rb
index f51dfba25218d..f695eda308b4b 100644
--- a/app/models/packages/package_file.rb
+++ b/app/models/packages/package_file.rb
@@ -45,7 +45,7 @@ class Packages::PackageFile < ApplicationRecord
   scope :with_file_name_like, ->(file_name) { where(arel_table[:file_name].matches(file_name)) }
   scope :with_files_stored_locally, -> { where(file_store: ::Packages::PackageFileUploader::Store::LOCAL) }
   scope :with_format, ->(format) { where(::Packages::PackageFile.arel_table[:file_name].matches("%.#{format}")) }
-  scope :with_nuget_format, -> { with_format(Packages::Nuget::FORMAT) }
+  scope :with_nuget_format, -> { where("reverse(split_part(reverse(packages_package_files.file_name), '.', 1)) = :format", format: Packages::Nuget::FORMAT) }
 
   scope :preload_package, -> { preload(:package) }
   scope :preload_pipelines, -> { preload(pipelines: :user) }
diff --git a/db/post_migrate/20240523145415_add_package_id_file_extension_status_index_to_package_files.rb b/db/post_migrate/20240523145415_add_package_id_file_extension_status_index_to_package_files.rb
new file mode 100644
index 0000000000000..f3a8f5309671a
--- /dev/null
+++ b/db/post_migrate/20240523145415_add_package_id_file_extension_status_index_to_package_files.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+class AddPackageIdFileExtensionStatusIndexToPackageFiles < Gitlab::Database::Migration[2.2]
+  milestone '17.1'
+  disable_ddl_transaction!
+
+  INDEX_NAME = 'index_packages_package_files_on_package_file_extension_status'
+  STATUS_INSTALLABLE = 0
+  EXT = 'nupkg'
+  INDEX_WHERE = "((status = #{STATUS_INSTALLABLE}) AND (reverse(split_part(reverse(file_name), '.', 1)) = '#{EXT}'))"
+
+  def up
+    add_concurrent_index :packages_package_files, :package_id, where: INDEX_WHERE, name: INDEX_NAME
+  end
+
+  def down
+    remove_concurrent_index_by_name :packages_package_files, name: INDEX_NAME
+  end
+end
diff --git a/db/schema_migrations/20240523145415 b/db/schema_migrations/20240523145415
new file mode 100644
index 0000000000000..77c6e3b6767ab
--- /dev/null
+++ b/db/schema_migrations/20240523145415
@@ -0,0 +1 @@
+ead3a46465678aef8267f2fe35f879d7cd459a8bc35ddfdc27f028983000e8fb
\ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 3d4e7ddb81afd..098d6e3fc5be3 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -27057,6 +27057,8 @@ CREATE INDEX index_packages_package_files_on_file_store ON packages_package_file
 
 CREATE INDEX index_packages_package_files_on_id_for_cleanup ON packages_package_files USING btree (id) WHERE (status = 1);
 
+CREATE INDEX index_packages_package_files_on_package_file_extension_status ON packages_package_files USING btree (package_id) WHERE ((status = 0) AND (reverse(split_part(reverse((file_name)::text), '.'::text, 1)) = 'nupkg'::text));
+
 CREATE INDEX index_packages_package_files_on_package_id_and_created_at_desc ON packages_package_files USING btree (package_id, created_at DESC);
 
 CREATE INDEX index_packages_package_files_on_package_id_and_file_name ON packages_package_files USING btree (package_id, file_name);
diff --git a/spec/models/packages/package_file_spec.rb b/spec/models/packages/package_file_spec.rb
index 6b7beb6646178..a3d5909486e60 100644
--- a/spec/models/packages/package_file_spec.rb
+++ b/spec/models/packages/package_file_spec.rb
@@ -8,7 +8,7 @@
   let_it_be(:package_file1) { create(:package_file, :xml, file_name: 'FooBar') }
   let_it_be(:package_file2) { create(:package_file, :xml, file_name: 'ThisIsATest') }
   let_it_be(:package_file3) { create(:package_file, :xml, file_name: 'formatted.zip') }
-  let_it_be(:package_file4) { create(:package_file, :nuget) }
+  let_it_be(:package_file4) { create(:package_file, :nuget, file_name: 'package-1.0.0.nupkg') }
   let_it_be(:package_file5) { create(:package_file, :xml, file_name: 'my_dir%2Fformatted') }
   let_it_be(:debian_package) { create(:debian_package, project: project, with_changes_file: true) }
 
-- 
GitLab