Skip to content
Snippets Groups Projects
Commit 3cbb7baf authored by Mario Celi's avatar Mario Celi :two: Committed by Krasimir Angelov
Browse files

Usage data related scopes use the work_item_types table

Scopes in lib/gitlab/usage_data.rb use the
work_item_types table to filter incidents

Changelog: other
parent cdc5c64f
No related branches found
No related tags found
1 merge request!121297Part 1: Usage data related scopes use the work_item_types table
Showing with 105 additions and 18 deletions
......@@ -220,8 +220,16 @@ def most_recent
duplicated_to: { project: [:project_feature] })
}
scope :with_issue_type, ->(types) {
types = Array(types)
if Feature.enabled?(:issue_type_uses_work_item_types_table)
joins(:work_item_type).where(work_item_types: { base_type: types })
# Using != 1 since we also want the guard clause to handle empty arrays
return joins(:work_item_type).where(work_item_types: { base_type: types }) if types.size != 1
where(
'"issues"."work_item_type_id" = (?)',
WorkItems::Type.by_type(types.first).select(:id).limit(1)
)
else
where(issue_type: types)
end
......
......@@ -3,7 +3,7 @@
class PrepareIssuesWorkItemTypeIdProjectIdIndex < Gitlab::Database::Migration[2.1]
INDEX_NAME = 'index_issues_on_work_item_type_id_project_id_created_at_state'
# TODO: Index to be created synchronously in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/120520
# TODO: Index to be created synchronously in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121297
def up
prepare_async_index :issues, [:work_item_type_id, :project_id, :created_at, :state_id], name: INDEX_NAME
end
......
# frozen_string_literal: true
class AddIssuesWorkItemTypeIdProjectIdIndex < Gitlab::Database::Migration[2.1]
INDEX_NAME = 'index_issues_on_work_item_type_id_project_id_created_at_state'
disable_ddl_transaction!
def up
add_concurrent_index :issues, [:work_item_type_id, :project_id, :created_at, :state_id], name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :issues, INDEX_NAME
end
end
# frozen_string_literal: true
class DropIndexIssuesOnWorkItemTypeId < Gitlab::Database::Migration[2.1]
INDEX_NAME = 'index_issues_on_work_item_type_id'
disable_ddl_transaction!
def up
remove_concurrent_index_by_name :issues, INDEX_NAME
end
def down
add_concurrent_index :issues, :work_item_type_id, name: INDEX_NAME
end
end
# frozen_string_literal: true
class CreateIndexAlertManagementAlertsOnCreatedAtProjectIdWithIssue < Gitlab::Database::Migration[2.1]
INDEX_NAME = 'idx_alert_management_alerts_on_created_at_project_id_with_issue'
disable_ddl_transaction!
def up
add_concurrent_index :alert_management_alerts, [:created_at, :project_id],
where: 'issue_id IS NOT NULL',
name: INDEX_NAME
end
def down
remove_concurrent_index_by_name :alert_management_alerts, INDEX_NAME
end
end
0565e50d50fa969c55f276f105e389819830591223aea399340a5288ef4618ee
\ No newline at end of file
83ec5273ae18c7dc8f554373df9c09e5b771912d5f093f455dd1e919a680e6ca
\ No newline at end of file
0537c5c23fc1a7e65780157a9bc4ee8db8a5d064779832c699222c5ab2e6e0eb
\ No newline at end of file
......@@ -29766,6 +29766,8 @@ CREATE UNIQUE INDEX i_pm_package_versions_on_package_id_and_version ON pm_packag
 
CREATE UNIQUE INDEX i_pm_packages_purl_type_and_name ON pm_packages USING btree (purl_type, name);
 
CREATE INDEX idx_alert_management_alerts_on_created_at_project_id_with_issue ON alert_management_alerts USING btree (created_at, project_id) WHERE (issue_id IS NOT NULL);
CREATE INDEX idx_analytics_devops_adoption_segments_on_namespace_id ON analytics_devops_adoption_segments USING btree (namespace_id);
 
CREATE INDEX idx_analytics_devops_adoption_snapshots_finalized ON analytics_devops_adoption_snapshots USING btree (namespace_id, end_time) WHERE (recorded_at >= end_time);
......@@ -31512,7 +31514,7 @@ CREATE INDEX index_issues_on_updated_at ON issues USING btree (updated_at);
 
CREATE INDEX index_issues_on_updated_by_id ON issues USING btree (updated_by_id) WHERE (updated_by_id IS NOT NULL);
 
CREATE INDEX index_issues_on_work_item_type_id ON issues USING btree (work_item_type_id);
CREATE INDEX index_issues_on_work_item_type_id_project_id_created_at_state ON issues USING btree (work_item_type_id, project_id, created_at, state_id);
 
CREATE INDEX index_iterations_cadences_on_group_id ON iterations_cadences USING btree (group_id);
 
......@@ -98,7 +98,7 @@ def system_usage_data
issues_using_zoom_quick_actions: distinct_count(ZoomMeeting, :issue_id),
issues_with_embedded_grafana_charts_approx: grafana_embed_usage_data,
issues_created_from_alerts: total_alert_issues,
incident_issues: count(::Issue.incident, start: minimum_id(Issue), finish: maximum_id(Issue)),
incident_issues: count(::Issue.with_issue_type(:incident), start: minimum_id(Issue), finish: maximum_id(Issue)),
alert_bot_incident_issues: count(::Issue.authored(::User.alert_bot), start: minimum_id(Issue), finish: maximum_id(Issue)),
keys: count(Key),
label_lists: count(List.label),
......@@ -110,7 +110,7 @@ def system_usage_data
pages_domains: count(PagesDomain),
pool_repositories: count(PoolRepository),
projects: count(Project),
projects_creating_incidents: distinct_count(Issue.incident, :project_id),
projects_creating_incidents: distinct_count(Issue.with_issue_type(:incident), :project_id),
projects_imported_from_github: count(Project.where(import_type: 'github')),
projects_with_repositories_enabled: count(ProjectFeature.where('repository_access_level > ?', ProjectFeature::DISABLED)),
projects_with_error_tracking_enabled: count(::ErrorTracking::ProjectErrorTrackingSetting.where(enabled: true)),
......@@ -447,8 +447,11 @@ def usage_activity_by_stage_monitor(time_period)
start: minimum_id(User),
finish: maximum_id(User)),
projects_with_error_tracking_enabled: distinct_count(::Project.with_enabled_error_tracking.where(time_period), :creator_id),
projects_with_incidents: distinct_count(::Issue.incident.where(time_period), :project_id),
projects_with_alert_incidents: distinct_count(::Issue.incident.with_alert_management_alerts.where(time_period), :project_id),
projects_with_incidents: distinct_count(::Issue.with_issue_type(:incident).where(time_period), :project_id),
# We are making an assumption here that all alert_management_alerts are associated with an issue of type
# incident. In reality this is very close to the truth and allows more efficient queries.
# More info in https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121297#note_1416999956
projects_with_alert_incidents: distinct_count(::AlertManagement::Alert.where(time_period).where.not(issue_id: nil), :project_id),
projects_with_enabled_alert_integrations_histogram: integrations_histogram
}.compact
end
......
......@@ -356,6 +356,8 @@ def omniauth_providers
create(:project_error_tracking_setting)
create(:incident)
create(:incident, alert_management_alert: create(:alert_management_alert))
create(:issue, alert_management_alert: create(:alert_management_alert))
create(:alert_management_alert)
create(:alert_management_http_integration, :active, project: project)
end
......@@ -365,7 +367,7 @@ def omniauth_providers
operations_dashboard_default_dashboard: 2,
projects_with_error_tracking_enabled: 2,
projects_with_incidents: 4,
projects_with_alert_incidents: 2,
projects_with_alert_incidents: 4,
projects_with_enabled_alert_integrations_histogram: { '1' => 2 }
)
......@@ -376,7 +378,7 @@ def omniauth_providers
operations_dashboard_default_dashboard: 1,
projects_with_error_tracking_enabled: 1,
projects_with_incidents: 2,
projects_with_alert_incidents: 1
projects_with_alert_incidents: 2
)
expect(data_28_days).not_to include(:projects_with_enabled_alert_integrations_histogram)
......
......@@ -433,15 +433,37 @@
.to contain_exactly(issue, incident)
end
it 'uses the work_item_types table for filtering' do
expect do
described_class.with_issue_type(:issue).to_a
end.to make_queries_matching(
%r{
INNER\sJOIN\s"work_item_types"\sON\s"work_item_types"\."id"\s=\s"issues"\."work_item_type_id"
\sWHERE\s"work_item_types"\."base_type"\s=\s0
}x
)
context 'when multiple issue_types are provided' do
it 'joins the work_item_types table for filtering' do
expect do
described_class.with_issue_type([:issue, :incident]).to_a
end.to make_queries_matching(
%r{
INNER\sJOIN\s"work_item_types"\sON\s"work_item_types"\."id"\s=\s"issues"\."work_item_type_id"
\sWHERE\s"work_item_types"\."base_type"\sIN\s\(0,\s1\)
}x
)
end
end
context 'when a single issue_type is provided' do
it 'uses an optimized query for a single work item type' do
expect do
described_class.with_issue_type([:incident]).to_a
end.to make_queries_matching(
%r{
WHERE\s\("issues"\."work_item_type_id"\s=
\s\(SELECT\s"work_item_types"\."id"\sFROM\s"work_item_types"\sWHERE\s"work_item_types"\."base_type"\s=\s1
\sLIMIT\s1\)\)
}x
)
end
end
context 'when no types are provided' do
it 'activerecord handles the false condition' do
expect(described_class.with_issue_type([]).to_sql).to include('WHERE 1=0')
end
end
context 'when the issue_type_uses_work_item_types_table feature flag is disabled' do
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment