diff --git a/lib/gitlab/database/query_analyzer.rb b/lib/gitlab/database/query_analyzer.rb
index 0c78dda734c734b7c2d10ddc355a11a07828b88a..6f64d04270fdbddb223dbb6c6cd222c75c1a5c77 100644
--- a/lib/gitlab/database/query_analyzer.rb
+++ b/lib/gitlab/database/query_analyzer.rb
@@ -30,52 +30,25 @@ def hook!
         end
       end
 
-      def within(user_analyzers = nil)
-        # Due to singleton nature of analyzers
-        # only an outer invocation of the `.within`
-        # is allowed to initialize them
-        if already_within?
-          raise 'Query analyzers are already defined, cannot re-define them.' if user_analyzers
-
-          return yield
-        end
-
-        begin!(user_analyzers || all_analyzers)
+      def within(analyzers = all_analyzers)
+        newly_enabled_analyzers = begin!(analyzers)
 
         begin
           yield
         ensure
-          end!
+          end!(newly_enabled_analyzers)
         end
       end
 
-      def already_within?
-        # If analyzers are set they are already configured
-        !enabled_analyzers.nil?
-      end
+      # Enable query analyzers (only the ones that were not yet enabled)
+      # Returns a list of newly enabled analyzers
+      def begin!(analyzers)
+        analyzers.select do |analyzer|
+          next if enabled_analyzers.include?(analyzer)
 
-      def process_sql(sql, connection)
-        analyzers = enabled_analyzers
-        return unless analyzers&.any?
-
-        parsed = parse(sql, connection)
-        return unless parsed
-
-        analyzers.each do |analyzer|
-          next if analyzer.suppressed? && !analyzer.requires_tracking?(parsed)
-
-          analyzer.analyze(parsed)
-        rescue StandardError, ::Gitlab::Database::QueryAnalyzers::Base::QueryAnalyzerError => e
-          # We catch all standard errors to prevent validation errors to introduce fatal errors in production
-          Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
-        end
-      end
-
-      # Enable query analyzers
-      def begin!(analyzers = all_analyzers)
-        analyzers = analyzers.select do |analyzer|
           if analyzer.enabled?
             analyzer.begin!
+            enabled_analyzers.append(analyzer)
 
             true
           end
@@ -84,25 +57,40 @@ def begin!(analyzers = all_analyzers)
 
           false
         end
-
-        Thread.current[:query_analyzer_enabled_analyzers] = analyzers
       end
 
-      # Disable enabled query analyzers
-      def end!
-        enabled_analyzers.select do |analyzer|
+      # Disable enabled query analyzers (only the ones that were enabled previously)
+      def end!(analyzers)
+        analyzers.each do |analyzer|
+          next unless enabled_analyzers.delete(analyzer)
+
           analyzer.end!
         rescue StandardError, ::Gitlab::Database::QueryAnalyzers::Base::QueryAnalyzerError => e
           Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
         end
-
-        Thread.current[:query_analyzer_enabled_analyzers] = nil
       end
 
       private
 
       def enabled_analyzers
-        Thread.current[:query_analyzer_enabled_analyzers]
+        Thread.current[:query_analyzer_enabled_analyzers] ||= []
+      end
+
+      def process_sql(sql, connection)
+        analyzers = enabled_analyzers
+        return unless analyzers&.any?
+
+        parsed = parse(sql, connection)
+        return unless parsed
+
+        analyzers.each do |analyzer|
+          next if analyzer.suppressed? && !analyzer.requires_tracking?(parsed)
+
+          analyzer.analyze(parsed)
+        rescue StandardError, ::Gitlab::Database::QueryAnalyzers::Base::QueryAnalyzerError => e
+          # We catch all standard errors to prevent validation errors to introduce fatal errors in production
+          Gitlab::ErrorTracking.track_and_raise_for_dev_exception(e)
+        end
       end
 
       def parse(sql, connection)
diff --git a/spec/lib/gitlab/database/query_analyzer_spec.rb b/spec/lib/gitlab/database/query_analyzer_spec.rb
index 3b4cbc79de2609909e265d1518d7db07b1d236c4..0b849063562a25e2cf9be95223122b16dee9c3e5 100644
--- a/spec/lib/gitlab/database/query_analyzer_spec.rb
+++ b/spec/lib/gitlab/database/query_analyzer_spec.rb
@@ -4,7 +4,7 @@
 
 RSpec.describe Gitlab::Database::QueryAnalyzer, query_analyzers: false do
   let(:analyzer) { double(:query_analyzer) }
-  let(:user_analyzer) { double(:query_analyzer) }
+  let(:user_analyzer) { double(:user_query_analyzer) }
   let(:disabled_analyzer) { double(:disabled_query_analyzer) }
 
   before do
@@ -49,14 +49,36 @@
         end
       end
 
-      it 'does not evaluate enabled? again do yield block' do
-        expect(analyzer).not_to receive(:enabled?)
+      it 'does initialize analyzer only once' do
+        expect(analyzer).to receive(:enabled?).once
+        expect(analyzer).to receive(:begin!).once
+        expect(analyzer).to receive(:end!).once
 
         expect { |b| described_class.instance.within(&b) }.to yield_control
       end
 
-      it 'raises exception when trying to re-define analyzers' do
-        expect { |b| described_class.instance.within([user_analyzer], &b) }.to raise_error /Query analyzers are already defined, cannot re-define them/
+      it 'does initialize user analyzer when enabled' do
+        expect(user_analyzer).to receive(:enabled?).and_return(true)
+        expect(user_analyzer).to receive(:begin!)
+        expect(user_analyzer).to receive(:end!)
+
+        expect { |b| described_class.instance.within([user_analyzer], &b) }.to yield_control
+      end
+
+      it 'does initialize user analyzer only once' do
+        expect(user_analyzer).to receive(:enabled?).and_return(false, true)
+        expect(user_analyzer).to receive(:begin!).once
+        expect(user_analyzer).to receive(:end!).once
+
+        expect { |b| described_class.instance.within([user_analyzer, user_analyzer, user_analyzer], &b) }.to yield_control
+      end
+
+      it 'does not initializer user analyzer when disabled' do
+        expect(user_analyzer).to receive(:enabled?).and_return(false)
+        expect(user_analyzer).not_to receive(:begin!)
+        expect(user_analyzer).not_to receive(:end!)
+
+        expect { |b| described_class.instance.within([user_analyzer], &b) }.to yield_control
       end
     end
 
@@ -162,7 +184,7 @@
     def process_sql(sql)
       described_class.instance.within do
         ApplicationRecord.load_balancer.read_write do |connection|
-          described_class.instance.process_sql(sql, connection)
+          described_class.instance.send(:process_sql, sql, connection)
         end
       end
     end
diff --git a/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb b/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb
index b8c1ecd908984bf9e3b9560863e4841b0642992a..0d687db0f961009469c499c3c97eb0aecbcdc3a6 100644
--- a/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb
+++ b/spec/lib/gitlab/database/query_analyzers/gitlab_schemas_metrics_spec.rb
@@ -140,7 +140,7 @@
   def process_sql(model, sql)
     Gitlab::Database::QueryAnalyzer.instance.within do
       # Skip load balancer and retrieve connection assigned to model
-      Gitlab::Database::QueryAnalyzer.instance.process_sql(sql, model.retrieve_connection)
+      Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection)
     end
   end
 end
diff --git a/spec/lib/gitlab/database/query_analyzers/restrict_allowed_schemas_spec.rb b/spec/lib/gitlab/database/query_analyzers/restrict_allowed_schemas_spec.rb
index a2c7916fa01e8c7ef08f9517087a42e1640c91ba..261bef58bb6e9ca00e548675b03baa0fa41bfa21 100644
--- a/spec/lib/gitlab/database/query_analyzers/restrict_allowed_schemas_spec.rb
+++ b/spec/lib/gitlab/database/query_analyzers/restrict_allowed_schemas_spec.rb
@@ -155,7 +155,7 @@ def process_sql(sql, model = ActiveRecord::Base)
       yield if block_given?
 
       # Skip load balancer and retrieve connection assigned to model
-      Gitlab::Database::QueryAnalyzer.instance.process_sql(sql, model.retrieve_connection)
+      Gitlab::Database::QueryAnalyzer.instance.send(:process_sql, sql, model.retrieve_connection)
     end
   end
 end
diff --git a/spec/support/database/query_analyzer.rb b/spec/support/database/query_analyzer.rb
index 6d6627d54b90312caea2cb3376f89e72fb0de279..aaa1b3516a327a88905736956966501130a98a0f 100644
--- a/spec/support/database/query_analyzer.rb
+++ b/spec/support/database/query_analyzer.rb
@@ -6,13 +6,17 @@
 RSpec.configure do |config|
   config.before do |example|
     if example.metadata.fetch(:query_analyzers, true)
-      ::Gitlab::Database::QueryAnalyzer.instance.begin!
+      ::Gitlab::Database::QueryAnalyzer.instance.begin!(
+        ::Gitlab::Database::QueryAnalyzer.instance.all_analyzers
+      )
     end
   end
 
   config.after do |example|
     if example.metadata.fetch(:query_analyzers, true)
-      ::Gitlab::Database::QueryAnalyzer.instance.end!
+      ::Gitlab::Database::QueryAnalyzer.instance.end!(
+        ::Gitlab::Database::QueryAnalyzer.instance.all_analyzers
+      )
     end
   end
 end