Issue:
Bug: fix(analytics): use HashSet to represent the returned metrics 



Currently we have 2 sources for analytics Clickhouse & Sqlx
Along with this we have a combined mode which helps compare for any differences in these results
However since currently we return a vector of results this causes an mismatch warning if the order is changed,
instead we should use a HashSet to store & compare these values.

https://github.com/juspay/hyperswitch/blob/d4dba55fedc37ba9d1d54d28456ca17851ab9881/crates/analytics/src/api_event/metrics.rs#L41-L50


we can also add a Counter metric to determine whenever these metrics are incorrect.

Pull request description:
## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [x] Bugfix
- [ ] New feature
- [x] Enhancement
- [ ] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [ ] CI/CD

## Description
<!-- Describe your changes in detail -->
Used hashset instead of vector for representing the returned metrics

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->
Currently we return a vector of results this causes an mismatch warning if the order is changed,
instead we should use a HashSet to store & compare these values.



## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->
Using curl requests, expected normal behaviour while perfoming payments, refunds, etc
```bash
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_IG9ateOUhGE0KLFEItNN1tsJXcr5M62N7zlbtOlUtStTfPpzSomswbQa4aO2k1B4' \
--data-raw '{
  "amount": 6540,
  "currency": "USD",
  "confirm": true,
  "capture_method": "automatic",
  "capture_on": "2022-09-10T10:11:12Z",
  "amount_to_capture": 6540,
  "customer_id": "StripeCustomer",
  "email": "guest@example.com",
  "name": "John Doe",
  "phone": "999999999",
  "phone_country_code": "+1",
  "description": "Its my first payment request",
  "authentication_type": "no_three_ds",
  "return_url": "https://google.com",
  "payment_method": "card",
  "payment_method_type": "credit",
  "payment_method_data": {
    "card": {
      "card_number": "4242424242424242",
      "card_exp_month": "10",
      "card_exp_year": "25",
      "card_holder_name": "joseph Doe",
      "card_cvc": "123"
    }
  },
  "billing": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "shipping": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "statement_descriptor_name": "joseph",
  "statement_descriptor_suffix": "JS",
  "metadata": {
    "data2": "camel",
    "new_customer": "true",
    "login_date": "2019-09-10T10:11:12Z"
  }
}'
```
<img width="1288" alt="Screenshot 2024-07-04 at 7 42 57 PM" src="https://github.com/juspay/hyperswitch/assets/83278309/e06f5709-d8ca-4fbc-a4ce-64059bf8088e">
<img width="640" alt="Screenshot 2024-07-04 at 7 43 31 PM" src="https://github.com/juspay/hyperswitch/assets/83278309/0edcffbc-004f-4df8-bb8b-d98a34ec88f2">

## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible


Testing:

Using curl requests, expected normal behaviour while perfoming payments, refunds, etc
```bash
curl --location 'http://localhost:8080/payments' \
--header 'Content-Type: application/json' \
--header 'Accept: application/json' \
--header 'api-key: dev_IG9ateOUhGE0KLFEItNN1tsJXcr5M62N7zlbtOlUtStTfPpzSomswbQa4aO2k1B4' \
--data-raw '{
  "amount": 6540,
  "currency": "USD",
  "confirm": true,
  "capture_method": "automatic",
  "capture_on": "2022-09-10T10:11:12Z",
  "amount_to_capture": 6540,
  "customer_id": "StripeCustomer",
  "email": "guest@example.com",
  "name": "John Doe",
  "phone": "999999999",
  "phone_country_code": "+1",
  "description": "Its my first payment request",
  "authentication_type": "no_three_ds",
  "return_url": "https://google.com",
  "payment_method": "card",
  "payment_method_type": "credit",
  "payment_method_data": {
    "card": {
      "card_number": "4242424242424242",
      "card_exp_month": "10",
      "card_exp_year": "25",
      "card_holder_name": "joseph Doe",
      "card_cvc": "123"
    }
  },
  "billing": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "shipping": {
    "address": {
      "line1": "1467",
      "line2": "Harrison Street",
      "line3": "Harrison Street",
      "city": "San Fransico",
      "state": "California",
      "zip": "94122",
      "country": "US",
      "first_name": "joseph",
      "last_name": "Doe"
    },
    "phone": {
      "number": "8056594427",
      "country_code": "+91"
    }
  },
  "statement_descriptor_name": "joseph",
  "statement_descriptor_suffix": "JS",
  "metadata": {
    "data2": "camel",
    "new_customer": "true",
    "login_date": "2019-09-10T10:11:12Z"
  }
}'
```
<img width="1288" alt="Screenshot 2024-07-04 at 7 42 57 PM" src="https://github.com/juspay/hyperswitch/assets/83278309/e06f5709-d8ca-4fbc-a4ce-64059bf8088e">
<img width="640" alt="Screenshot 2024-07-04 at 7 43 31 PM" src="https://github.com/juspay/hyperswitch/assets/83278309/0edcffbc-004f-4df8-bb8b-d98a34ec88f2">

Patch:
diff --git a/crates/analytics/src/active_payments/metrics.rs b/crates/analytics/src/active_payments/metrics.rs
index e7b4ff3f5b6..5526f30fd6e 100644
--- a/crates/analytics/src/active_payments/metrics.rs
+++ b/crates/analytics/src/active_payments/metrics.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     active_payments::{ActivePaymentsMetrics, ActivePaymentsMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -13,7 +15,7 @@ mod active_payments;
 
 use active_payments::ActivePayments;
 
-#[derive(Debug, PartialEq, Eq, serde::Deserialize)]
+#[derive(Debug, PartialEq, Eq, serde::Deserialize, Hash)]
 pub struct ActivePaymentsMetricRow {
     pub count: Option<i64>,
 }
@@ -32,7 +34,7 @@ where
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<
-        Vec<(
+        HashSet<(
             ActivePaymentsMetricsBucketIdentifier,
             ActivePaymentsMetricRow,
         )>,
@@ -56,7 +58,7 @@ where
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<
-        Vec<(
+        HashSet<(
             ActivePaymentsMetricsBucketIdentifier,
             ActivePaymentsMetricRow,
         )>,
diff --git a/crates/analytics/src/active_payments/metrics/active_payments.rs b/crates/analytics/src/active_payments/metrics/active_payments.rs
index 60209e39755..30621c98c7e 100644
--- a/crates/analytics/src/active_payments/metrics/active_payments.rs
+++ b/crates/analytics/src/active_payments/metrics/active_payments.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     active_payments::ActivePaymentsMetricsBucketIdentifier, Granularity, TimeRange,
 };
@@ -31,7 +33,7 @@ where
         time_range: &TimeRange,
         pool: &T,
     ) -> MetricsResult<
-        Vec<(
+        HashSet<(
             ActivePaymentsMetricsBucketIdentifier,
             ActivePaymentsMetricRow,
         )>,
@@ -79,7 +81,7 @@ where
             .into_iter()
             .map(|i| Ok((ActivePaymentsMetricsBucketIdentifier::new(None), i)))
             .collect::<error_stack::Result<
-                Vec<(
+                HashSet<(
                     ActivePaymentsMetricsBucketIdentifier,
                     ActivePaymentsMetricRow,
                 )>,
diff --git a/crates/analytics/src/api_event/metrics.rs b/crates/analytics/src/api_event/metrics.rs
index 16f2d7a2f5a..1a08b56a595 100644
--- a/crates/analytics/src/api_event/metrics.rs
+++ b/crates/analytics/src/api_event/metrics.rs
@@ -14,13 +14,15 @@ use crate::{
 mod api_count;
 pub mod latency;
 mod status_code_count;
+use std::collections::HashSet;
+
 use api_count::ApiCount;
 use latency::MaxLatency;
 use status_code_count::StatusCodeCount;
 
 use self::latency::LatencyAvg;
 
-#[derive(Debug, PartialEq, Eq, serde::Deserialize)]
+#[derive(Debug, PartialEq, Eq, serde::Deserialize, Hash)]
 pub struct ApiEventMetricRow {
     pub latency: Option<u64>,
     pub api_count: Option<u64>,
@@ -46,7 +48,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>>;
+    ) -> MetricsResult<HashSet<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>>;
 }
 
 #[async_trait::async_trait]
@@ -67,7 +69,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>> {
         match self {
             Self::Latency => {
                 MaxLatency
diff --git a/crates/analytics/src/api_event/metrics/api_count.rs b/crates/analytics/src/api_event/metrics/api_count.rs
index 7f5f291aa53..cb9d559292d 100644
--- a/crates/analytics/src/api_event/metrics/api_count.rs
+++ b/crates/analytics/src/api_event/metrics/api_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     api_event::{ApiEventDimensions, ApiEventFilters, ApiEventMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -33,7 +35,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::ApiEvents);
 
         query_builder
@@ -98,7 +100,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>,
+                HashSet<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/api_event/metrics/latency.rs b/crates/analytics/src/api_event/metrics/latency.rs
index 379b39fbeb9..20fb6489451 100644
--- a/crates/analytics/src/api_event/metrics/latency.rs
+++ b/crates/analytics/src/api_event/metrics/latency.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     api_event::{ApiEventDimensions, ApiEventFilters, ApiEventMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -36,7 +38,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::ApiEvents);
 
         query_builder
@@ -120,7 +122,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>,
+                HashSet<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/api_event/metrics/status_code_count.rs b/crates/analytics/src/api_event/metrics/status_code_count.rs
index 5c652fd8e0c..a5130169213 100644
--- a/crates/analytics/src/api_event/metrics/status_code_count.rs
+++ b/crates/analytics/src/api_event/metrics/status_code_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     api_event::{ApiEventDimensions, ApiEventFilters, ApiEventMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -33,7 +35,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::ApiEvents);
 
         query_builder
@@ -95,7 +97,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>,
+                HashSet<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/auth_events/metrics.rs b/crates/analytics/src/auth_events/metrics.rs
index ae61aefb858..6690850a80e 100644
--- a/crates/analytics/src/auth_events/metrics.rs
+++ b/crates/analytics/src/auth_events/metrics.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     auth_events::{AuthEventMetrics, AuthEventMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -27,7 +29,7 @@ use frictionless_flow_count::FrictionlessFlowCount;
 use frictionless_success_count::FrictionlessSuccessCount;
 use three_ds_sdk_count::ThreeDsSdkCount;
 
-#[derive(Debug, PartialEq, Eq, serde::Deserialize)]
+#[derive(Debug, PartialEq, Eq, serde::Deserialize, Hash)]
 pub struct AuthEventMetricRow {
     pub count: Option<i64>,
     pub time_bucket: Option<String>,
@@ -47,7 +49,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>>;
+    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>>;
 }
 
 #[async_trait::async_trait]
@@ -67,7 +69,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         match self {
             Self::ThreeDsSdkCount => {
                 ThreeDsSdkCount
diff --git a/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs b/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs
index 01110858804..80c80db92fe 100644
--- a/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs
+++ b/crates/analytics/src/auth_events/metrics/authentication_attempt_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity,
     TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
 
@@ -94,7 +96,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
+                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/auth_events/metrics/authentication_success_count.rs b/crates/analytics/src/auth_events/metrics/authentication_success_count.rs
index 6f0580bb0b5..bfcfbaf3a6a 100644
--- a/crates/analytics/src/auth_events/metrics/authentication_success_count.rs
+++ b/crates/analytics/src/auth_events/metrics/authentication_success_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity,
     TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
 
@@ -94,7 +96,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
+                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs b/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs
index f2d2ab153f0..b146c053d3d 100644
--- a/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs
+++ b/crates/analytics/src/auth_events/metrics/challenge_attempt_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     auth_events::{AuthEventFlows, AuthEventMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::ApiEventsAnalytics);
 
@@ -86,7 +88,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
+                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs b/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs
index 49fef8941f7..b2921bb3ece 100644
--- a/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs
+++ b/crates/analytics/src/auth_events/metrics/challenge_flow_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity,
     TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
 
@@ -96,7 +98,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
+                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/auth_events/metrics/challenge_success_count.rs b/crates/analytics/src/auth_events/metrics/challenge_success_count.rs
index b7d55714b60..f6553f84f8c 100644
--- a/crates/analytics/src/auth_events/metrics/challenge_success_count.rs
+++ b/crates/analytics/src/auth_events/metrics/challenge_success_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     auth_events::{AuthEventFlows, AuthEventMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::ApiEventsAnalytics);
 
@@ -86,7 +88,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
+                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs b/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs
index 7ae9d773675..42261f09b3e 100644
--- a/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs
+++ b/crates/analytics/src/auth_events/metrics/frictionless_flow_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity,
     TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
 
@@ -98,7 +100,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
+                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs b/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs
index 2f05a050ce7..4d7eed972f4 100644
--- a/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs
+++ b/crates/analytics/src/auth_events/metrics/frictionless_success_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     auth_events::{AuthEventFlows, AuthEventMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::ApiEventsAnalytics);
 
@@ -86,7 +88,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
+                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/auth_events/metrics/three_ds_sdk_count.rs b/crates/analytics/src/auth_events/metrics/three_ds_sdk_count.rs
index b08d48b550a..05173bcb9da 100644
--- a/crates/analytics/src/auth_events/metrics/three_ds_sdk_count.rs
+++ b/crates/analytics/src/auth_events/metrics/three_ds_sdk_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     auth_events::AuthEventMetricsBucketIdentifier, sdk_events::SdkEventNames, Granularity,
     TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
 
@@ -94,7 +96,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
+                HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/disputes/metrics.rs b/crates/analytics/src/disputes/metrics.rs
index 4963626d0fa..e397785528c 100644
--- a/crates/analytics/src/disputes/metrics.rs
+++ b/crates/analytics/src/disputes/metrics.rs
@@ -2,6 +2,8 @@ mod dispute_status_metric;
 mod total_amount_disputed;
 mod total_dispute_lost_amount;
 
+use std::collections::HashSet;
+
 use api_models::{
     analytics::{
         disputes::{
@@ -22,7 +24,7 @@ use crate::{
     query::{Aggregate, GroupByClause, ToSql, Window},
     types::{AnalyticsCollection, AnalyticsDataSource, DBEnumWrapper, LoadRow, MetricsResult},
 };
-#[derive(Debug, Eq, PartialEq, serde::Deserialize)]
+#[derive(Debug, Eq, PartialEq, serde::Deserialize, Hash)]
 pub struct DisputeMetricRow {
     pub dispute_stage: Option<DBEnumWrapper<storage_enums::DisputeStage>>,
     pub dispute_status: Option<DBEnumWrapper<storage_enums::DisputeStatus>>,
@@ -55,7 +57,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>>;
+    ) -> MetricsResult<HashSet<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>>;
 }
 
 #[async_trait::async_trait]
@@ -76,7 +78,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>> {
+    ) -> MetricsResult<HashSet<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>> {
         match self {
             Self::TotalAmountDisputed => {
                 TotalAmountDisputed::default()
diff --git a/crates/analytics/src/disputes/metrics/dispute_status_metric.rs b/crates/analytics/src/disputes/metrics/dispute_status_metric.rs
index 5b97021becc..005be320eb5 100644
--- a/crates/analytics/src/disputes/metrics/dispute_status_metric.rs
+++ b/crates/analytics/src/disputes/metrics/dispute_status_metric.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     disputes::{DisputeDimensions, DisputeFilters, DisputeMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>>
+    ) -> MetricsResult<HashSet<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>>
     where
         T: AnalyticsDataSource + super::DisputeMetricAnalytics,
     {
@@ -111,7 +113,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>,
+                HashSet<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/disputes/metrics/total_amount_disputed.rs b/crates/analytics/src/disputes/metrics/total_amount_disputed.rs
index cbba553aa85..cf299ebfa9d 100644
--- a/crates/analytics/src/disputes/metrics/total_amount_disputed.rs
+++ b/crates/analytics/src/disputes/metrics/total_amount_disputed.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     disputes::{DisputeDimensions, DisputeFilters, DisputeMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>>
+    ) -> MetricsResult<HashSet<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>>
     where
         T: AnalyticsDataSource + super::DisputeMetricAnalytics,
     {
@@ -110,7 +112,7 @@ where
                     i,
                 ))
             })
-            .collect::<error_stack::Result<Vec<_>, crate::query::PostProcessingError>>()
+            .collect::<error_stack::Result<HashSet<_>, crate::query::PostProcessingError>>()
             .change_context(MetricsError::PostProcessingFailure)
     }
 }
diff --git a/crates/analytics/src/disputes/metrics/total_dispute_lost_amount.rs b/crates/analytics/src/disputes/metrics/total_dispute_lost_amount.rs
index c7be2ab1a98..ddf6338f01f 100644
--- a/crates/analytics/src/disputes/metrics/total_dispute_lost_amount.rs
+++ b/crates/analytics/src/disputes/metrics/total_dispute_lost_amount.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     disputes::{DisputeDimensions, DisputeFilters, DisputeMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>>
+    ) -> MetricsResult<HashSet<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>>
     where
         T: AnalyticsDataSource + super::DisputeMetricAnalytics,
     {
@@ -111,7 +113,7 @@ where
                     i,
                 ))
             })
-            .collect::<error_stack::Result<Vec<_>, crate::query::PostProcessingError>>()
+            .collect::<error_stack::Result<HashSet<_>, crate::query::PostProcessingError>>()
             .change_context(MetricsError::PostProcessingFailure)
     }
 }
diff --git a/crates/analytics/src/lib.rs b/crates/analytics/src/lib.rs
index 943ac9a5311..d6812100c8a 100644
--- a/crates/analytics/src/lib.rs
+++ b/crates/analytics/src/lib.rs
@@ -31,7 +31,7 @@ pub use types::AnalyticsDomain;
 pub mod lambda_utils;
 pub mod utils;
 
-use std::sync::Arc;
+use std::{collections::HashSet, sync::Arc};
 
 use api_models::analytics::{
     active_payments::{ActivePaymentsMetrics, ActivePaymentsMetricsBucketIdentifier},
@@ -113,7 +113,7 @@ impl AnalyticsProvider {
         filters: &PaymentFilters,
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
-    ) -> types::MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+    ) -> types::MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
         // Metrics to get the fetch time for each payment metric
         metrics::request::record_operation_time(
             async {
@@ -327,7 +327,7 @@ impl AnalyticsProvider {
         filters: &PaymentIntentFilters,
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
-    ) -> types::MetricsResult<Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>
+    ) -> types::MetricsResult<HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>
     {
         // Metrics to get the fetch time for each payment intent metric
         metrics::request::record_operation_time(
@@ -432,7 +432,7 @@ impl AnalyticsProvider {
         filters: &RefundFilters,
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
-    ) -> types::MetricsResult<Vec<(RefundMetricsBucketIdentifier, RefundMetricRow)>> {
+    ) -> types::MetricsResult<HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>> {
         // Metrics to get the fetch time for each refund metric
         metrics::request::record_operation_time(
             async {
@@ -532,7 +532,7 @@ impl AnalyticsProvider {
         filters: &DisputeFilters,
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
-    ) -> types::MetricsResult<Vec<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>> {
+    ) -> types::MetricsResult<HashSet<(DisputeMetricsBucketIdentifier, DisputeMetricRow)>> {
         // Metrics to get the fetch time for each refund metric
         metrics::request::record_operation_time(
             async {
@@ -632,7 +632,7 @@ impl AnalyticsProvider {
         filters: &SdkEventFilters,
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
-    ) -> types::MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
+    ) -> types::MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
         match self {
             Self::Sqlx(_pool) => Err(report!(MetricsError::NotImplemented)),
             Self::Clickhouse(pool) => {
@@ -670,7 +670,7 @@ impl AnalyticsProvider {
         publishable_key: &str,
         time_range: &TimeRange,
     ) -> types::MetricsResult<
-        Vec<(
+        HashSet<(
             ActivePaymentsMetricsBucketIdentifier,
             ActivePaymentsMetricRow,
         )>,
@@ -697,7 +697,7 @@ impl AnalyticsProvider {
         publishable_key: &str,
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
-    ) -> types::MetricsResult<Vec<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
+    ) -> types::MetricsResult<HashSet<(AuthEventMetricsBucketIdentifier, AuthEventMetricRow)>> {
         match self {
             Self::Sqlx(_pool) => Err(report!(MetricsError::NotImplemented)),
             Self::Clickhouse(pool) => {
@@ -728,7 +728,7 @@ impl AnalyticsProvider {
         filters: &ApiEventFilters,
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
-    ) -> types::MetricsResult<Vec<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>> {
+    ) -> types::MetricsResult<HashSet<(ApiEventMetricsBucketIdentifier, ApiEventMetricRow)>> {
         match self {
             Self::Sqlx(_pool) => Err(report!(MetricsError::NotImplemented)),
             Self::Clickhouse(ckh_pool)
diff --git a/crates/analytics/src/payment_intents/core.rs b/crates/analytics/src/payment_intents/core.rs
index e3932baaf07..c7546a4ab0d 100644
--- a/crates/analytics/src/payment_intents/core.rs
+++ b/crates/analytics/src/payment_intents/core.rs
@@ -1,5 +1,5 @@
 #![allow(dead_code)]
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 
 use api_models::analytics::{
     payment_intents::{
@@ -34,7 +34,7 @@ pub enum TaskType {
     MetricTask(
         PaymentIntentMetrics,
         CustomResult<
-            Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
+            HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
             AnalyticsError,
         >,
     ),
diff --git a/crates/analytics/src/payment_intents/metrics.rs b/crates/analytics/src/payment_intents/metrics.rs
index 3a0cbbc85db..a06d76ce8fe 100644
--- a/crates/analytics/src/payment_intents/metrics.rs
+++ b/crates/analytics/src/payment_intents/metrics.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     payment_intents::{
         PaymentIntentDimensions, PaymentIntentFilters, PaymentIntentMetrics,
@@ -23,7 +25,7 @@ use smart_retried_amount::SmartRetriedAmount;
 use successful_smart_retries::SuccessfulSmartRetries;
 use total_smart_retries::TotalSmartRetries;
 
-#[derive(Debug, PartialEq, Eq, serde::Deserialize)]
+#[derive(Debug, PartialEq, Eq, serde::Deserialize, Hash)]
 pub struct PaymentIntentMetricRow {
     pub status: Option<DBEnumWrapper<storage_enums::IntentStatus>>,
     pub currency: Option<DBEnumWrapper<storage_enums::Currency>>,
@@ -50,7 +52,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>;
+    ) -> MetricsResult<HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>;
 }
 
 #[async_trait::async_trait]
@@ -71,7 +73,8 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>
+    {
         match self {
             Self::SuccessfulSmartRetries => {
                 SuccessfulSmartRetries
diff --git a/crates/analytics/src/payment_intents/metrics/payment_intent_count.rs b/crates/analytics/src/payment_intents/metrics/payment_intent_count.rs
index 0f235375c4f..5db153c8a36 100644
--- a/crates/analytics/src/payment_intents/metrics/payment_intent_count.rs
+++ b/crates/analytics/src/payment_intents/metrics/payment_intent_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     payment_intents::{
         PaymentIntentDimensions, PaymentIntentFilters, PaymentIntentMetricsBucketIdentifier,
@@ -35,7 +37,8 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>
+    {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::PaymentIntent);
 
@@ -113,7 +116,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
+                HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/payment_intents/metrics/smart_retried_amount.rs b/crates/analytics/src/payment_intents/metrics/smart_retried_amount.rs
index 470a0e66867..3b78a355828 100644
--- a/crates/analytics/src/payment_intents/metrics/smart_retried_amount.rs
+++ b/crates/analytics/src/payment_intents/metrics/smart_retried_amount.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::{
     analytics::{
         payment_intents::{
@@ -41,7 +43,8 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>
+    {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::PaymentIntent);
 
@@ -123,7 +126,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
+                HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/payment_intents/metrics/successful_smart_retries.rs b/crates/analytics/src/payment_intents/metrics/successful_smart_retries.rs
index 292062d1e10..ef0bb6672f1 100644
--- a/crates/analytics/src/payment_intents/metrics/successful_smart_retries.rs
+++ b/crates/analytics/src/payment_intents/metrics/successful_smart_retries.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::{
     analytics::{
         payment_intents::{
@@ -41,7 +43,8 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>
+    {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::PaymentIntent);
 
@@ -122,7 +125,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
+                HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/payment_intents/metrics/total_smart_retries.rs b/crates/analytics/src/payment_intents/metrics/total_smart_retries.rs
index d5a3d142baf..3ef8c02aca2 100644
--- a/crates/analytics/src/payment_intents/metrics/total_smart_retries.rs
+++ b/crates/analytics/src/payment_intents/metrics/total_smart_retries.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     payment_intents::{
         PaymentIntentDimensions, PaymentIntentFilters, PaymentIntentMetricsBucketIdentifier,
@@ -38,7 +40,8 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>>
+    {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::PaymentIntent);
 
@@ -117,7 +120,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
+                HashSet<(PaymentIntentMetricsBucketIdentifier, PaymentIntentMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/payments/core.rs b/crates/analytics/src/payments/core.rs
index 2508866626a..e943bf0ac6b 100644
--- a/crates/analytics/src/payments/core.rs
+++ b/crates/analytics/src/payments/core.rs
@@ -1,5 +1,5 @@
 #![allow(dead_code)]
-use std::collections::HashMap;
+use std::collections::{HashMap, HashSet};
 
 use api_models::analytics::{
     payments::{
@@ -34,7 +34,7 @@ use crate::{
 pub enum TaskType {
     MetricTask(
         PaymentMetrics,
-        CustomResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>, AnalyticsError>,
+        CustomResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>, AnalyticsError>,
     ),
     DistributionTask(
         PaymentDistributions,
diff --git a/crates/analytics/src/payments/metrics.rs b/crates/analytics/src/payments/metrics.rs
index 59a9ca88a84..1dd1481688f 100644
--- a/crates/analytics/src/payments/metrics.rs
+++ b/crates/analytics/src/payments/metrics.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     payments::{PaymentDimensions, PaymentFilters, PaymentMetrics, PaymentMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -27,7 +29,7 @@ use success_rate::PaymentSuccessRate;
 
 use self::retries_count::RetriesCount;
 
-#[derive(Debug, PartialEq, Eq, serde::Deserialize)]
+#[derive(Debug, PartialEq, Eq, serde::Deserialize, Hash)]
 pub struct PaymentMetricRow {
     pub currency: Option<DBEnumWrapper<storage_enums::Currency>>,
     pub status: Option<DBEnumWrapper<storage_enums::AttemptStatus>>,
@@ -60,7 +62,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>>;
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>>;
 }
 
 #[async_trait::async_trait]
@@ -81,7 +83,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
         match self {
             Self::PaymentSuccessRate => {
                 PaymentSuccessRate
diff --git a/crates/analytics/src/payments/metrics/avg_ticket_size.rs b/crates/analytics/src/payments/metrics/avg_ticket_size.rs
index 38ab0a9540d..1a1fbe52987 100644
--- a/crates/analytics/src/payments/metrics/avg_ticket_size.rs
+++ b/crates/analytics/src/payments/metrics/avg_ticket_size.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -34,7 +36,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
         let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Payment);
 
         for dim in dimensions.iter() {
@@ -130,7 +132,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
+                HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/payments/metrics/connector_success_rate.rs b/crates/analytics/src/payments/metrics/connector_success_rate.rs
index 2742327f4ab..c5da4b51a0b 100644
--- a/crates/analytics/src/payments/metrics/connector_success_rate.rs
+++ b/crates/analytics/src/payments/metrics/connector_success_rate.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -36,7 +38,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
         let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Payment);
         let mut dimensions = dimensions.to_vec();
 
@@ -124,7 +126,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
+                HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/payments/metrics/payment_count.rs b/crates/analytics/src/payments/metrics/payment_count.rs
index 50ea1791b39..6fd12edea74 100644
--- a/crates/analytics/src/payments/metrics/payment_count.rs
+++ b/crates/analytics/src/payments/metrics/payment_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -33,7 +35,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
         let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Payment);
 
         for dim in dimensions.iter() {
@@ -115,7 +117,7 @@ where
                     i,
                 ))
             })
-            .collect::<error_stack::Result<Vec<_>, crate::query::PostProcessingError>>()
+            .collect::<error_stack::Result<HashSet<_>, crate::query::PostProcessingError>>()
             .change_context(MetricsError::PostProcessingFailure)
     }
 }
diff --git a/crates/analytics/src/payments/metrics/payment_processed_amount.rs b/crates/analytics/src/payments/metrics/payment_processed_amount.rs
index 6ea5b15734f..772156a070d 100644
--- a/crates/analytics/src/payments/metrics/payment_processed_amount.rs
+++ b/crates/analytics/src/payments/metrics/payment_processed_amount.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -34,7 +36,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
         let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Payment);
 
         for dim in dimensions.iter() {
@@ -124,7 +126,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
+                HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/payments/metrics/payment_success_count.rs b/crates/analytics/src/payments/metrics/payment_success_count.rs
index 4350700618e..ce63424d1c8 100644
--- a/crates/analytics/src/payments/metrics/payment_success_count.rs
+++ b/crates/analytics/src/payments/metrics/payment_success_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -34,7 +36,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
         let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Payment);
 
         for dim in dimensions.iter() {
@@ -123,7 +125,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
+                HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/payments/metrics/retries_count.rs b/crates/analytics/src/payments/metrics/retries_count.rs
index 3c4580d37a7..33aa7d3b0b6 100644
--- a/crates/analytics/src/payments/metrics/retries_count.rs
+++ b/crates/analytics/src/payments/metrics/retries_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::{
     analytics::{
         payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
@@ -39,7 +41,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::PaymentIntent);
         query_builder
@@ -119,7 +121,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
+                HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/payments/metrics/success_rate.rs b/crates/analytics/src/payments/metrics/success_rate.rs
index a0c67c1d807..1f48deaad16 100644
--- a/crates/analytics/src/payments/metrics/success_rate.rs
+++ b/crates/analytics/src/payments/metrics/success_rate.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     payments::{PaymentDimensions, PaymentFilters, PaymentMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -33,7 +35,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
+    ) -> MetricsResult<HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>> {
         let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Payment);
         let mut dimensions = dimensions.to_vec();
 
@@ -119,7 +121,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
+                HashSet<(PaymentMetricsBucketIdentifier, PaymentMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/refunds/metrics.rs b/crates/analytics/src/refunds/metrics.rs
index 10cd0354677..d8a59e54888 100644
--- a/crates/analytics/src/refunds/metrics.rs
+++ b/crates/analytics/src/refunds/metrics.rs
@@ -10,6 +10,8 @@ mod refund_count;
 mod refund_processed_amount;
 mod refund_success_count;
 mod refund_success_rate;
+use std::collections::HashSet;
+
 use refund_count::RefundCount;
 use refund_processed_amount::RefundProcessedAmount;
 use refund_success_count::RefundSuccessCount;
@@ -19,7 +21,8 @@ use crate::{
     query::{Aggregate, GroupByClause, ToSql, Window},
     types::{AnalyticsCollection, AnalyticsDataSource, DBEnumWrapper, LoadRow, MetricsResult},
 };
-#[derive(Debug, Eq, PartialEq, serde::Deserialize)]
+
+#[derive(Debug, Eq, PartialEq, serde::Deserialize, Hash)]
 pub struct RefundMetricRow {
     pub currency: Option<DBEnumWrapper<storage_enums::Currency>>,
     pub refund_status: Option<DBEnumWrapper<storage_enums::RefundStatus>>,
@@ -53,7 +56,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(RefundMetricsBucketIdentifier, RefundMetricRow)>>;
+    ) -> MetricsResult<HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>>;
 }
 
 #[async_trait::async_trait]
@@ -74,7 +77,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(RefundMetricsBucketIdentifier, RefundMetricRow)>> {
+    ) -> MetricsResult<HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>> {
         match self {
             Self::RefundSuccessRate => {
                 RefundSuccessRate::default()
diff --git a/crates/analytics/src/refunds/metrics/refund_count.rs b/crates/analytics/src/refunds/metrics/refund_count.rs
index cf3c7a50927..14240ff8e13 100644
--- a/crates/analytics/src/refunds/metrics/refund_count.rs
+++ b/crates/analytics/src/refunds/metrics/refund_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     refunds::{RefundDimensions, RefundFilters, RefundMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -33,7 +35,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(RefundMetricsBucketIdentifier, RefundMetricRow)>> {
+    ) -> MetricsResult<HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>> {
         let mut query_builder: QueryBuilder<T> = QueryBuilder::new(AnalyticsCollection::Refund);
 
         for dim in dimensions.iter() {
@@ -111,7 +113,7 @@ where
                     i,
                 ))
             })
-            .collect::<error_stack::Result<Vec<_>, crate::query::PostProcessingError>>()
+            .collect::<error_stack::Result<HashSet<_>, crate::query::PostProcessingError>>()
             .change_context(MetricsError::PostProcessingFailure)
     }
 }
diff --git a/crates/analytics/src/refunds/metrics/refund_processed_amount.rs b/crates/analytics/src/refunds/metrics/refund_processed_amount.rs
index 661fca57b28..829b11b082c 100644
--- a/crates/analytics/src/refunds/metrics/refund_processed_amount.rs
+++ b/crates/analytics/src/refunds/metrics/refund_processed_amount.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     refunds::{RefundDimensions, RefundFilters, RefundMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -33,7 +35,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(RefundMetricsBucketIdentifier, RefundMetricRow)>>
+    ) -> MetricsResult<HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>>
     where
         T: AnalyticsDataSource + super::RefundMetricAnalytics,
     {
@@ -117,7 +119,7 @@ where
                     i,
                 ))
             })
-            .collect::<error_stack::Result<Vec<_>, crate::query::PostProcessingError>>()
+            .collect::<error_stack::Result<HashSet<_>, crate::query::PostProcessingError>>()
             .change_context(MetricsError::PostProcessingFailure)
     }
 }
diff --git a/crates/analytics/src/refunds/metrics/refund_success_count.rs b/crates/analytics/src/refunds/metrics/refund_success_count.rs
index bc09d8b7ab6..0219340b40b 100644
--- a/crates/analytics/src/refunds/metrics/refund_success_count.rs
+++ b/crates/analytics/src/refunds/metrics/refund_success_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     refunds::{RefundDimensions, RefundFilters, RefundMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -34,7 +36,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(RefundMetricsBucketIdentifier, RefundMetricRow)>>
+    ) -> MetricsResult<HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>>
     where
         T: AnalyticsDataSource + super::RefundMetricAnalytics,
     {
@@ -115,7 +117,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(RefundMetricsBucketIdentifier, RefundMetricRow)>,
+                HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/refunds/metrics/refund_success_rate.rs b/crates/analytics/src/refunds/metrics/refund_success_rate.rs
index 29b73b885d8..36d82385b3f 100644
--- a/crates/analytics/src/refunds/metrics/refund_success_rate.rs
+++ b/crates/analytics/src/refunds/metrics/refund_success_rate.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     refunds::{RefundDimensions, RefundFilters, RefundMetricsBucketIdentifier},
     Granularity, TimeRange,
@@ -32,7 +34,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(RefundMetricsBucketIdentifier, RefundMetricRow)>>
+    ) -> MetricsResult<HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>>
     where
         T: AnalyticsDataSource + super::RefundMetricAnalytics,
     {
@@ -110,7 +112,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(RefundMetricsBucketIdentifier, RefundMetricRow)>,
+                HashSet<(RefundMetricsBucketIdentifier, RefundMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/sdk_events/metrics.rs b/crates/analytics/src/sdk_events/metrics.rs
index 50481084e4b..7d5ad0c53d4 100644
--- a/crates/analytics/src/sdk_events/metrics.rs
+++ b/crates/analytics/src/sdk_events/metrics.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     sdk_events::{
         SdkEventDimensions, SdkEventFilters, SdkEventMetrics, SdkEventMetricsBucketIdentifier,
@@ -29,7 +31,7 @@ use payment_methods_call_count::PaymentMethodsCallCount;
 use sdk_initiated_count::SdkInitiatedCount;
 use sdk_rendered_count::SdkRenderedCount;
 
-#[derive(Debug, PartialEq, Eq, serde::Deserialize)]
+#[derive(Debug, PartialEq, Eq, serde::Deserialize, Hash)]
 pub struct SdkEventMetricRow {
     pub total: Option<bigdecimal::BigDecimal>,
     pub count: Option<i64>,
@@ -57,7 +59,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>>;
+    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>>;
 }
 
 #[async_trait::async_trait]
@@ -78,7 +80,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
         match self {
             Self::PaymentAttempts => {
                 PaymentAttempts
diff --git a/crates/analytics/src/sdk_events/metrics/average_payment_time.rs b/crates/analytics/src/sdk_events/metrics/average_payment_time.rs
index 88c96d33efb..c7f6bca988c 100644
--- a/crates/analytics/src/sdk_events/metrics/average_payment_time.rs
+++ b/crates/analytics/src/sdk_events/metrics/average_payment_time.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     sdk_events::{
         SdkEventDimensions, SdkEventFilters, SdkEventMetricsBucketIdentifier, SdkEventNames,
@@ -35,7 +37,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
         let dimensions = dimensions.to_vec();
@@ -116,7 +118,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
+                HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/sdk_events/metrics/load_time.rs b/crates/analytics/src/sdk_events/metrics/load_time.rs
index 4624f304295..73cc693c506 100644
--- a/crates/analytics/src/sdk_events/metrics/load_time.rs
+++ b/crates/analytics/src/sdk_events/metrics/load_time.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     sdk_events::{
         SdkEventDimensions, SdkEventFilters, SdkEventMetricsBucketIdentifier, SdkEventNames,
@@ -35,7 +37,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
         let dimensions = dimensions.to_vec();
@@ -116,7 +118,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
+                HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/sdk_events/metrics/payment_attempts.rs b/crates/analytics/src/sdk_events/metrics/payment_attempts.rs
index 7cbe93056a9..4d949d9fb82 100644
--- a/crates/analytics/src/sdk_events/metrics/payment_attempts.rs
+++ b/crates/analytics/src/sdk_events/metrics/payment_attempts.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     sdk_events::{
         SdkEventDimensions, SdkEventFilters, SdkEventMetricsBucketIdentifier, SdkEventNames,
@@ -35,7 +37,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
         let dimensions = dimensions.to_vec();
@@ -111,7 +113,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
+                HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/sdk_events/metrics/payment_data_filled_count.rs b/crates/analytics/src/sdk_events/metrics/payment_data_filled_count.rs
index aff78808d1d..37eb967b385 100644
--- a/crates/analytics/src/sdk_events/metrics/payment_data_filled_count.rs
+++ b/crates/analytics/src/sdk_events/metrics/payment_data_filled_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     sdk_events::{
         SdkEventDimensions, SdkEventFilters, SdkEventMetricsBucketIdentifier, SdkEventNames,
@@ -35,7 +37,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
         let dimensions = dimensions.to_vec();
@@ -111,7 +113,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
+                HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/sdk_events/metrics/payment_method_selected_count.rs b/crates/analytics/src/sdk_events/metrics/payment_method_selected_count.rs
index 284519441a7..d524d0021cf 100644
--- a/crates/analytics/src/sdk_events/metrics/payment_method_selected_count.rs
+++ b/crates/analytics/src/sdk_events/metrics/payment_method_selected_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     sdk_events::{
         SdkEventDimensions, SdkEventFilters, SdkEventMetricsBucketIdentifier, SdkEventNames,
@@ -35,7 +37,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
         let dimensions = dimensions.to_vec();
@@ -111,7 +113,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
+                HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/sdk_events/metrics/payment_methods_call_count.rs b/crates/analytics/src/sdk_events/metrics/payment_methods_call_count.rs
index e7dc6504036..081c4968c53 100644
--- a/crates/analytics/src/sdk_events/metrics/payment_methods_call_count.rs
+++ b/crates/analytics/src/sdk_events/metrics/payment_methods_call_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     sdk_events::{
         SdkEventDimensions, SdkEventFilters, SdkEventMetricsBucketIdentifier, SdkEventNames,
@@ -35,7 +37,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
         let dimensions = dimensions.to_vec();
@@ -119,7 +121,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
+                HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/sdk_events/metrics/sdk_initiated_count.rs b/crates/analytics/src/sdk_events/metrics/sdk_initiated_count.rs
index 82c2096a2e4..92308acac69 100644
--- a/crates/analytics/src/sdk_events/metrics/sdk_initiated_count.rs
+++ b/crates/analytics/src/sdk_events/metrics/sdk_initiated_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     sdk_events::{
         SdkEventDimensions, SdkEventFilters, SdkEventMetricsBucketIdentifier, SdkEventNames,
@@ -35,7 +37,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
         let dimensions = dimensions.to_vec();
@@ -111,7 +113,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
+                HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/sdk_events/metrics/sdk_rendered_count.rs b/crates/analytics/src/sdk_events/metrics/sdk_rendered_count.rs
index eba94f0d9ad..6f03008e0c1 100644
--- a/crates/analytics/src/sdk_events/metrics/sdk_rendered_count.rs
+++ b/crates/analytics/src/sdk_events/metrics/sdk_rendered_count.rs
@@ -1,3 +1,5 @@
+use std::collections::HashSet;
+
 use api_models::analytics::{
     sdk_events::{
         SdkEventDimensions, SdkEventFilters, SdkEventMetricsBucketIdentifier, SdkEventNames,
@@ -35,7 +37,7 @@ where
         granularity: &Option<Granularity>,
         time_range: &TimeRange,
         pool: &T,
-    ) -> MetricsResult<Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
+    ) -> MetricsResult<HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>> {
         let mut query_builder: QueryBuilder<T> =
             QueryBuilder::new(AnalyticsCollection::SdkEventsAnalytics);
         let dimensions = dimensions.to_vec();
@@ -111,7 +113,7 @@ where
                 ))
             })
             .collect::<error_stack::Result<
-                Vec<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
+                HashSet<(SdkEventMetricsBucketIdentifier, SdkEventMetricRow)>,
                 crate::query::PostProcessingError,
             >>()
             .change_context(MetricsError::PostProcessingFailure)
diff --git a/crates/analytics/src/types.rs b/crates/analytics/src/types.rs
index 816c77fd304..4323b40a887 100644
--- a/crates/analytics/src/types.rs
+++ b/crates/analytics/src/types.rs
@@ -44,7 +44,7 @@ pub enum TableEngine {
     BasicTree,
 }
 
-#[derive(Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq)]
+#[derive(Debug, serde::Serialize, serde::Deserialize, Eq, PartialEq, Hash)]
 #[serde(transparent)]
 pub struct DBEnumWrapper<T: FromStr + Display>(pub T);
 
diff --git a/crates/api_models/src/analytics/refunds.rs b/crates/api_models/src/analytics/refunds.rs
index 5ecdf1cecb3..32e3abaf37a 100644
--- a/crates/api_models/src/analytics/refunds.rs
+++ b/crates/api_models/src/analytics/refunds.rs
@@ -10,6 +10,7 @@ use crate::{enums::Currency, refunds::RefundStatus};
     Copy,
     Debug,
     Default,
+    Hash,
     Eq,
     PartialEq,
     serde::Serialize,
diff --git a/crates/common_enums/src/enums.rs b/crates/common_enums/src/enums.rs
index 2ad0ad35cb3..7e320c8c367 100644
--- a/crates/common_enums/src/enums.rs
+++ b/crates/common_enums/src/enums.rs
@@ -25,6 +25,7 @@ pub mod diesel_exports {
     Copy,
     Debug,
     Default,
+    Hash,
     Eq,
     PartialEq,
     serde::Deserialize,