yumeng há 1 mês atrás
pai
commit
88e0620e00

+ 1 - 0
src/main/java/com/adx/tencent/AppConfiguration.java

@@ -630,6 +630,7 @@ public class AppConfiguration {
                 mainSchema,
                 props.getReportDatabaseName(),
                 props.getAdBidReportRetentionDays(),
+                props.getTrackingReportRetentionDays(),
                 props.getAdBidReportArchiveBatchSize(),
                 props.getAdBidReportArchiveMaxBatchesPerRun(),
                 props.getAdBidReportStatsLookbackDays());

+ 9 - 0
src/main/java/com/adx/tencent/config/AppProperties.java

@@ -123,6 +123,7 @@ public class AppProperties {
     private boolean adBidReportEnabled = false;
     private Duration adBidReportInterval = Duration.ofMinutes(5);
     private int adBidReportRetentionDays = 30;
+    private int trackingReportRetentionDays = 3;
     private int adBidReportArchiveBatchSize = 5000;
     private int adBidReportArchiveMaxBatchesPerRun = 20;
     private List<String> adBidReportStatsRunTimes = List.of("01:00", "10:00", "17:00");
@@ -878,6 +879,14 @@ public class AppProperties {
         this.adBidReportRetentionDays = v;
     }
 
+    public int getTrackingReportRetentionDays() {
+        return trackingReportRetentionDays;
+    }
+
+    public void setTrackingReportRetentionDays(int v) {
+        this.trackingReportRetentionDays = v;
+    }
+
     public int getAdBidReportArchiveBatchSize() {
         return adBidReportArchiveBatchSize;
     }

+ 4 - 0
src/main/java/com/adx/tencent/honor/store/HonorColdStore.java

@@ -112,6 +112,10 @@ public class HonorColdStore {
             }
             stmt.execute("UPDATE honor_ad_bid_events SET price = 0 WHERE price IS NULL");
             stmt.execute("ALTER TABLE honor_ad_bid_events MODIFY COLUMN price BIGINT UNSIGNED NOT NULL DEFAULT 0");
+            try {
+                stmt.execute("ALTER TABLE honor_tracking_reports ADD KEY idx_honor_tracking_reports_created_at_id (created_at, id)");
+            } catch (Exception ignored) {
+            }
             stmt.close();
         } catch (Exception e) {
             throw new RuntimeException("honor migrate failed", e);

+ 4 - 0
src/main/java/com/adx/tencent/kuaishou/store/KuaishouColdStore.java

@@ -114,6 +114,10 @@ public class KuaishouColdStore {
                 stmt.execute("ALTER TABLE kuaishou_tag_event DROP PRIMARY KEY, ADD PRIMARY KEY (tag_id, baidu_act, event_type)");
             } catch (Exception ignored) {
             }
+            try {
+                stmt.execute("ALTER TABLE kuaishou_tracking_reports ADD KEY idx_kuaishou_tracking_reports_created_at_id (created_at, id)");
+            } catch (Exception ignored) {
+            }
             stmt.close();
         } catch (Exception e) {
             throw new RuntimeException("kuaishou migrate failed", e);

+ 2 - 1
src/main/java/com/adx/tencent/report/AdBidReportBackgroundTasks.java

@@ -76,8 +76,9 @@ public class AdBidReportBackgroundTasks implements ApplicationRunner {
                     lastStatsSlotKey = currentStatsSlotKey;
                 }
                 ZonedDateTime nextStatsAt = nextStatsRunAt(now, statsRunTimes);
-                log.info("[AdBidReport] done | archivedRows={} | statsRows={} | statsRun={} | nextStatsAt={}",
+                log.info("[AdBidReport] done | archivedRows={} | archivedTrackingRows={} | statsRows={} | statsRun={} | nextStatsAt={}",
                         summary.archivedRows,
+                        summary.archivedTrackingRows,
                         summary.statsRows,
                         summary.statsRun,
                         nextStatsAt == null ? "-" : nextStatsAt);

+ 163 - 64
src/main/java/com/adx/tencent/report/AdBidReportStore.java

@@ -21,6 +21,7 @@ public class AdBidReportStore {
     private final String mainSchema;
     private final String reportSchema;
     private final int retentionDays;
+    private final int trackingRetentionDays;
     private final int archiveBatchSize;
     private final int archiveMaxBatchesPerRun;
     private final int statsLookbackDays;
@@ -29,6 +30,7 @@ public class AdBidReportStore {
                             String mainSchema,
                             String reportSchema,
                             int retentionDays,
+                            int trackingRetentionDays,
                             int archiveBatchSize,
                             int archiveMaxBatchesPerRun,
                             int statsLookbackDays) {
@@ -36,6 +38,7 @@ public class AdBidReportStore {
         this.mainSchema = safeIdentifier(mainSchema);
         this.reportSchema = safeIdentifier(reportSchema == null || reportSchema.isBlank() ? "adx_report" : reportSchema);
         this.retentionDays = Math.max(retentionDays, 1);
+        this.trackingRetentionDays = Math.max(trackingRetentionDays, 1);
         this.archiveBatchSize = Math.max(archiveBatchSize, 100);
         this.archiveMaxBatchesPerRun = Math.max(archiveMaxBatchesPerRun, 1);
         this.statsLookbackDays = Math.max(statsLookbackDays, 1);
@@ -51,6 +54,7 @@ public class AdBidReportStore {
                     ps.execute();
                 }
                 ensureDailyStatsColumns(conn, media);
+                ensureTrackingHotIndexes(conn, media);
             }
         } catch (Exception e) {
             throw new RuntimeException("ad bid report migrate failed", e);
@@ -63,11 +67,13 @@ public class AdBidReportStore {
 
     public RunSummary runOnce(boolean includeStats) {
         RunSummary summary = new RunSummary();
-        Timestamp cutoff = Timestamp.from(Instant.now().minusSeconds(retentionDays * 24L * 3600L));
+        Timestamp adBidCutoff = Timestamp.from(Instant.now().minusSeconds(retentionDays * 24L * 3600L));
+        Timestamp trackingCutoff = Timestamp.from(Instant.now().minusSeconds(trackingRetentionDays * 24L * 3600L));
         try (Connection conn = dataSource.getConnection()) {
             conn.setAutoCommit(false);
             for (MediaTable media : MediaTable.values()) {
-                summary.archivedRows += archiveMedia(conn, media, cutoff);
+                summary.archivedRows += archiveMedia(conn, media, adBidCutoff);
+                summary.archivedTrackingRows += archiveTrackingMedia(conn, media, trackingCutoff);
                 if (includeStats) {
                     summary.statsRows += rollupStats(conn, media);
                     summary.statsRun = true;
@@ -81,19 +87,19 @@ public class AdBidReportStore {
     }
 
     private long archiveMedia(Connection conn, MediaTable media, Timestamp cutoff) throws Exception {
-        List<YearMonth> months = listArchivableMonths(conn, media, cutoff);
+        List<YearMonth> months = listArchivableMonths(conn, media.hotTable, cutoff);
         long archived = 0L;
         for (YearMonth month : months) {
             ensureHistoryTable(conn, media, month);
             Timestamp monthStart = Timestamp.valueOf(month.atDay(1).atStartOfDay());
             Timestamp monthEnd = Timestamp.valueOf(month.plusMonths(1).atDay(1).atStartOfDay());
             for (int i = 0; i < archiveMaxBatchesPerRun; i++) {
-                List<Long> candidateIds = selectArchiveCandidateIds(conn, media, monthStart, monthEnd, cutoff);
+                List<Long> candidateIds = selectArchiveCandidateIds(conn, media.hotTable, monthStart, monthEnd, cutoff);
                 if (candidateIds.isEmpty()) {
                     break;
                 }
                 insertHistoryBatch(conn, media, month, candidateIds);
-                int deleted = deleteHotBatch(conn, media, month, candidateIds);
+                int deleted = deleteHotBatch(conn, media.hotTable, historyTable(media, month), candidateIds);
                 if (deleted > 0) {
                     archived += deleted;
                 }
@@ -105,24 +111,6 @@ public class AdBidReportStore {
         return archived;
     }
 
-    private List<YearMonth> listArchivableMonths(Connection conn, MediaTable media, Timestamp cutoff) throws Exception {
-        String sql = "SELECT DATE_FORMAT(created_at, '%Y%m') AS ym FROM `" + mainSchema + "`.`" + media.hotTable + "` " +
-                "WHERE created_at < ? GROUP BY ym ORDER BY ym ASC";
-        List<YearMonth> result = new ArrayList<>();
-        try (PreparedStatement ps = conn.prepareStatement(sql)) {
-            ps.setTimestamp(1, cutoff);
-            try (ResultSet rs = ps.executeQuery()) {
-                while (rs.next()) {
-                    String ym = rs.getString("ym");
-                    if (ym != null && ym.length() == 6) {
-                        result.add(YearMonth.of(Integer.parseInt(ym.substring(0, 4)), Integer.parseInt(ym.substring(4, 6))));
-                    }
-                }
-            }
-        }
-        return result;
-    }
-
     private void ensureHistoryTable(Connection conn, MediaTable media, YearMonth month) throws Exception {
         String table = historyTable(media, month);
         String sql = "CREATE TABLE IF NOT EXISTS `" + reportSchema + "`.`" + table + "` LIKE `" +
@@ -132,29 +120,6 @@ public class AdBidReportStore {
         }
     }
 
-    private List<Long> selectArchiveCandidateIds(Connection conn,
-                                                 MediaTable media,
-                                                 Timestamp monthStart,
-                                                 Timestamp monthEnd,
-                                                 Timestamp cutoff) throws Exception {
-        String sql = "SELECT id FROM `" + mainSchema + "`.`" + media.hotTable + "` " +
-                "WHERE created_at >= ? AND created_at < ? AND created_at < ? " +
-                "ORDER BY created_at ASC, id ASC LIMIT ?";
-        List<Long> ids = new ArrayList<>(archiveBatchSize);
-        try (PreparedStatement ps = conn.prepareStatement(sql)) {
-            ps.setTimestamp(1, monthStart);
-            ps.setTimestamp(2, monthEnd);
-            ps.setTimestamp(3, cutoff);
-            ps.setInt(4, archiveBatchSize);
-            try (ResultSet rs = ps.executeQuery()) {
-                while (rs.next()) {
-                    ids.add(rs.getLong(1));
-                }
-            }
-        }
-        return ids;
-    }
-
     private void insertHistoryBatch(Connection conn,
                                     MediaTable media,
                                     YearMonth month,
@@ -170,19 +135,6 @@ public class AdBidReportStore {
         }
     }
 
-    private int deleteHotBatch(Connection conn,
-                               MediaTable media,
-                               YearMonth month,
-                               List<Long> candidateIds) throws Exception {
-        String historyTable = historyTable(media, month);
-        String sql = "DELETE hot FROM `" + mainSchema + "`.`" + media.hotTable + "` hot " +
-                "INNER JOIN `" + reportSchema + "`.`" + historyTable + "` hist ON hist.id = hot.id " +
-                "WHERE hot.id IN (" + placeholders(candidateIds.size()) + ")";
-        try (PreparedStatement ps = conn.prepareStatement(sql)) {
-            bindIds(ps, candidateIds, 1);
-            return ps.executeUpdate();
-        }
-    }
 
     private long rollupStats(Connection conn, MediaTable media) throws Exception {
         LocalDate endExclusiveDate = LocalDate.now(ZONE);
@@ -220,10 +172,39 @@ public class AdBidReportStore {
         }
     }
 
+    private long archiveTrackingMedia(Connection conn, MediaTable media, Timestamp cutoff) throws Exception {
+        List<YearMonth> months = listArchivableMonths(conn, media.trackingHotTable, cutoff);
+        long archived = 0L;
+        for (YearMonth month : months) {
+            ensureTrackingHistoryTable(conn, media, month);
+            Timestamp monthStart = Timestamp.valueOf(month.atDay(1).atStartOfDay());
+            Timestamp monthEnd = Timestamp.valueOf(month.plusMonths(1).atDay(1).atStartOfDay());
+            for (int i = 0; i < archiveMaxBatchesPerRun; i++) {
+                List<Long> candidateIds = selectArchiveCandidateIds(conn, media.trackingHotTable, monthStart, monthEnd, cutoff);
+                if (candidateIds.isEmpty()) {
+                    break;
+                }
+                insertTrackingHistoryBatch(conn, media, month, candidateIds);
+                int deleted = deleteHotBatch(conn, media.trackingHotTable, trackingHistoryTable(media, month), candidateIds);
+                if (deleted > 0) {
+                    archived += deleted;
+                }
+                if (deleted == 0) {
+                    break;
+                }
+            }
+        }
+        return archived;
+    }
+
     private String historyTable(MediaTable media, YearMonth month) {
         return media.historyPrefix + month.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMM", Locale.ROOT));
     }
 
+    private String trackingHistoryTable(MediaTable media, YearMonth month) {
+        return media.trackingHistoryPrefix + month.format(java.time.format.DateTimeFormatter.ofPattern("yyyyMM", Locale.ROOT));
+    }
+
     private String createDailyStatsDdl(MediaTable media) {
         return "CREATE TABLE IF NOT EXISTS `" + reportSchema + "`.`" + media.statsTable + "` (" +
                 "id BIGINT AUTO_INCREMENT PRIMARY KEY," +
@@ -258,6 +239,111 @@ public class AdBidReportStore {
                 "MODIFY COLUMN price_sum BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'price>0记录数'");
     }
 
+    private List<YearMonth> listArchivableMonths(Connection conn, String hotTable, Timestamp cutoff) throws Exception {
+        String sql = "SELECT DATE_FORMAT(created_at, '%Y%m') AS ym FROM `" + mainSchema + "`.`" + hotTable + "` " +
+                "WHERE created_at < ? GROUP BY ym ORDER BY ym ASC";
+        List<YearMonth> result = new ArrayList<>();
+        try (PreparedStatement ps = conn.prepareStatement(sql)) {
+            ps.setTimestamp(1, cutoff);
+            try (ResultSet rs = ps.executeQuery()) {
+                while (rs.next()) {
+                    String ym = rs.getString("ym");
+                    if (ym != null && ym.length() == 6) {
+                        result.add(YearMonth.of(Integer.parseInt(ym.substring(0, 4)), Integer.parseInt(ym.substring(4, 6))));
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    private List<Long> selectArchiveCandidateIds(Connection conn,
+                                                 String hotTable,
+                                                 Timestamp monthStart,
+                                                 Timestamp monthEnd,
+                                                 Timestamp cutoff) throws Exception {
+        String sql = "SELECT id FROM `" + mainSchema + "`.`" + hotTable + "` " +
+                "WHERE created_at >= ? AND created_at < ? AND created_at < ? " +
+                "ORDER BY created_at ASC, id ASC LIMIT ?";
+        List<Long> ids = new ArrayList<>(archiveBatchSize);
+        try (PreparedStatement ps = conn.prepareStatement(sql)) {
+            ps.setTimestamp(1, monthStart);
+            ps.setTimestamp(2, monthEnd);
+            ps.setTimestamp(3, cutoff);
+            ps.setInt(4, archiveBatchSize);
+            try (ResultSet rs = ps.executeQuery()) {
+                while (rs.next()) {
+                    ids.add(rs.getLong(1));
+                }
+            }
+        }
+        return ids;
+    }
+
+    private void ensureTrackingHistoryTable(Connection conn, MediaTable media, YearMonth month) throws Exception {
+        String table = trackingHistoryTable(media, month);
+        StringBuilder ddl = new StringBuilder();
+        ddl.append("CREATE TABLE IF NOT EXISTS `").append(reportSchema).append("`.`").append(table).append("` (")
+                .append("id BIGINT NOT NULL PRIMARY KEY COMMENT '热表原始ID',")
+                .append("qk VARCHAR(128) DEFAULT NULL COMMENT '关联业务键',");
+        if (media.trackingHasTagId) {
+            ddl.append("tag_id VARCHAR(128) NOT NULL COMMENT '百度广告位ID',");
+        }
+        ddl.append("kind VARCHAR(32) NOT NULL COMMENT '类型(impression/click)',")
+                .append("status INT NOT NULL COMMENT 'HTTP响应状态码',")
+                .append("ok TINYINT(1) NOT NULL COMMENT '是否成功(1=成功,0=失败)',")
+                .append("created_at TIMESTAMP(3) NOT NULL COMMENT '创建时间',")
+                .append("KEY `idx_").append(table).append("_created_at` (created_at),")
+                .append("KEY `idx_").append(table).append("_qk_kind_created_at` (qk, kind, created_at)");
+        if (media.trackingHasTagId) {
+            ddl.append(",KEY `idx_").append(table).append("_tag_created_at` (tag_id, created_at)");
+        }
+        ddl.append(") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='").append(media.comment).append(" tracking历史归档'");
+        try (PreparedStatement ps = conn.prepareStatement(ddl.toString())) {
+            ps.execute();
+        }
+    }
+
+    private void insertTrackingHistoryBatch(Connection conn,
+                                            MediaTable media,
+                                            YearMonth month,
+                                            List<Long> candidateIds) throws Exception {
+        String table = trackingHistoryTable(media, month);
+        String targetCols = media.trackingHasTagId
+                ? "(id, qk, tag_id, kind, status, ok, created_at) "
+                : "(id, qk, kind, status, ok, created_at) ";
+        String selectCols = media.trackingHasTagId
+                ? "SELECT id, qk, tag_id, kind, status, ok, created_at "
+                : "SELECT id, qk, kind, status, ok, created_at ";
+        String sql = "INSERT IGNORE INTO `" + reportSchema + "`.`" + table + "` " + targetCols +
+                selectCols +
+                "FROM `" + mainSchema + "`.`" + media.trackingHotTable + "` " +
+                "WHERE id IN (" + placeholders(candidateIds.size()) + ") " +
+                "ORDER BY created_at ASC, id ASC";
+        try (PreparedStatement ps = conn.prepareStatement(sql)) {
+            bindIds(ps, candidateIds, 1);
+            ps.executeUpdate();
+        }
+    }
+
+    private int deleteHotBatch(Connection conn,
+                               String hotTable,
+                               String historyTable,
+                               List<Long> candidateIds) throws Exception {
+        String sql = "DELETE hot FROM `" + mainSchema + "`.`" + hotTable + "` hot " +
+                "INNER JOIN `" + reportSchema + "`.`" + historyTable + "` hist ON hist.id = hot.id " +
+                "WHERE hot.id IN (" + placeholders(candidateIds.size()) + ")";
+        try (PreparedStatement ps = conn.prepareStatement(sql)) {
+            bindIds(ps, candidateIds, 1);
+            return ps.executeUpdate();
+        }
+    }
+
+    private void ensureTrackingHotIndexes(Connection conn, MediaTable media) {
+        tryAlter(conn, "ALTER TABLE `" + mainSchema + "`.`" + media.trackingHotTable + "` " +
+                "ADD INDEX `idx_" + media.trackingHotTable + "_created_at_id` (created_at, id)");
+    }
+
     private static void tryAlter(Connection conn, String sql) {
         try (PreparedStatement ps = conn.prepareStatement(sql)) {
             ps.execute();
@@ -295,25 +381,38 @@ public class AdBidReportStore {
 
     public static class RunSummary {
         public long archivedRows;
+        public long archivedTrackingRows;
         public long statsRows;
         public boolean statsRun;
     }
 
     private enum MediaTable {
-        TENCENT("tencent_ad_bid_events", "tencent_ad_bid_events_history_", "tencent_ad_bid_events_daily_stats", "腾讯"),
-        HONOR("honor_ad_bid_events", "honor_ad_bid_events_history_", "honor_ad_bid_events_daily_stats", "荣耀"),
-        KUAISHOU("kuaishou_ad_bid_events", "kuaishou_ad_bid_events_history_", "kuaishou_ad_bid_events_daily_stats", "快手"),
-        VIVO("vivo_ad_bid_events", "vivo_ad_bid_events_history_", "vivo_ad_bid_events_daily_stats", "vivo");
+        TENCENT("tencent_ad_bid_events", "tencent_ad_bid_events_history_", "tencent_ad_bid_events_daily_stats",
+                "tencent_tracking_reports", "tencent_tracking_reports_history_", false, "腾讯"),
+        HONOR("honor_ad_bid_events", "honor_ad_bid_events_history_", "honor_ad_bid_events_daily_stats",
+                "honor_tracking_reports", "honor_tracking_reports_history_", true, "荣耀"),
+        KUAISHOU("kuaishou_ad_bid_events", "kuaishou_ad_bid_events_history_", "kuaishou_ad_bid_events_daily_stats",
+                "kuaishou_tracking_reports", "kuaishou_tracking_reports_history_", true, "快手"),
+        VIVO("vivo_ad_bid_events", "vivo_ad_bid_events_history_", "vivo_ad_bid_events_daily_stats",
+                "vivo_tracking_reports", "vivo_tracking_reports_history_", true, "vivo");
 
         private final String hotTable;
         private final String historyPrefix;
         private final String statsTable;
+        private final String trackingHotTable;
+        private final String trackingHistoryPrefix;
+        private final boolean trackingHasTagId;
         private final String comment;
 
-        MediaTable(String hotTable, String historyPrefix, String statsTable, String comment) {
+        MediaTable(String hotTable, String historyPrefix, String statsTable,
+                   String trackingHotTable, String trackingHistoryPrefix,
+                   boolean trackingHasTagId, String comment) {
             this.hotTable = hotTable;
             this.historyPrefix = historyPrefix;
             this.statsTable = statsTable;
+            this.trackingHotTable = trackingHotTable;
+            this.trackingHistoryPrefix = trackingHistoryPrefix;
+            this.trackingHasTagId = trackingHasTagId;
             this.comment = comment;
         }
     }

+ 3 - 0
src/main/java/com/adx/tencent/storage/TiDBColdStore.java

@@ -167,6 +167,9 @@ public class TiDBColdStore {
                 stmt.execute("ALTER TABLE tencent_media_callbacks ADD COLUMN dispatch_status VARCHAR(32) NOT NULL DEFAULT 'SENT' AFTER request_body");
             } catch (Exception ignored) {}
             try {
+                stmt.execute("ALTER TABLE tencent_tracking_reports ADD KEY idx_tencent_tracking_reports_created_at_id (created_at, id)");
+            } catch (Exception ignored) {}
+            try {
                 stmt.execute("UPDATE tencent_media_callbacks SET dispatch_status = 'SENT' WHERE dispatch_status IS NULL OR dispatch_status = ''");
             } catch (Exception ignored) {}
             try {

+ 4 - 0
src/main/java/com/adx/tencent/vivo/store/VivoColdStore.java

@@ -192,6 +192,10 @@ public class VivoColdStore {
                 stmt.execute("ALTER TABLE vivo_account_tokens ADD COLUMN client_secret VARCHAR(1024) COMMENT '本次授权使用的vivo API client_secret快照' AFTER client_id");
             } catch (Exception ignored) {
             }
+            try {
+                stmt.execute("ALTER TABLE vivo_tracking_reports ADD KEY idx_vivo_tracking_reports_created_at_id (created_at, id)");
+            } catch (Exception ignored) {
+            }
             stmt.close();
         } catch (Exception e) {
             throw new RuntimeException("vivo migrate failed", e);

+ 1 - 0
src/main/resources/application-dev.yml

@@ -66,6 +66,7 @@ adx:
   ad-bid-report-enabled: false
   ad-bid-report-interval: 5m
   ad-bid-report-retention-days: 30
+  tracking-report-retention-days: 3
   ad-bid-report-archive-batch-size: 5000
   ad-bid-report-archive-max-batches-per-run: 20
   ad-bid-report-stats-run-times: ["01:00", "10:00", "17:00"]

+ 1 - 0
src/main/resources/application-prod.yml

@@ -68,6 +68,7 @@ adx:
   ad-bid-report-enabled: true
   ad-bid-report-interval: 5m
   ad-bid-report-retention-days: 30
+  tracking-report-retention-days: 3
   ad-bid-report-archive-batch-size: 5000
   ad-bid-report-archive-max-batches-per-run: 20
   ad-bid-report-stats-run-times: ["01:00", "10:00", "17:00"]

+ 1 - 0
src/main/resources/application-test.yml

@@ -67,6 +67,7 @@ adx:
   ad-bid-report-enabled: true
   ad-bid-report-interval: 5m
   ad-bid-report-retention-days: 30
+  tracking-report-retention-days: 3
   ad-bid-report-archive-batch-size: 5000
   ad-bid-report-archive-max-batches-per-run: 20
   ad-bid-report-stats-run-times: ["01:00", "10:00", "17:00"]

+ 2 - 1
src/main/resources/schema-honor.sql

@@ -42,7 +42,8 @@ CREATE TABLE IF NOT EXISTS honor_tracking_reports (
     ok TINYINT(1) NOT NULL COMMENT '是否成功(1=成功,0=失败)',
     created_at TIMESTAMP(3) NOT NULL COMMENT '创建时间',
     KEY idx_honor_tracking_reports_qk_kind_created_at (qk, kind, created_at),
-    KEY idx_honor_tracking_reports_tag_created_at (tag_id, created_at)
+    KEY idx_honor_tracking_reports_tag_created_at (tag_id, created_at),
+    KEY idx_honor_tracking_reports_created_at_id (created_at, id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='荣耀曝光/点击上报结果';
 
 -- ------------------------------------------------------------

+ 2 - 1
src/main/resources/schema-kuaishou.sql

@@ -27,7 +27,8 @@ CREATE TABLE IF NOT EXISTS kuaishou_tracking_reports (
     ok TINYINT(1) NOT NULL COMMENT '是否成功(1=成功,0=失败)',
     created_at TIMESTAMP(3) NOT NULL COMMENT '创建时间',
     KEY idx_kuaishou_tracking_reports_qk_kind_created_at (qk, kind, created_at),
-    KEY idx_kuaishou_tracking_reports_tag_created_at (tag_id, created_at)
+    KEY idx_kuaishou_tracking_reports_tag_created_at (tag_id, created_at),
+    KEY idx_kuaishou_tracking_reports_created_at_id (created_at, id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='快手曝光/点击上报结果';
 
 CREATE TABLE IF NOT EXISTS kuaishou_media_callbacks (

+ 2 - 1
src/main/resources/schema-vivo.sql

@@ -28,7 +28,8 @@ CREATE TABLE IF NOT EXISTS vivo_tracking_reports (
     ok TINYINT(1) NOT NULL COMMENT '是否成功(1=成功,0=失败)',
     created_at TIMESTAMP(3) NOT NULL COMMENT '创建时间',
     KEY idx_vivo_tracking_reports_qk_kind_created_at (qk, kind, created_at),
-    KEY idx_vivo_tracking_reports_tag_created_at (tag_id, created_at)
+    KEY idx_vivo_tracking_reports_tag_created_at (tag_id, created_at),
+    KEY idx_vivo_tracking_reports_created_at_id (created_at, id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='vivo曝光/点击上报结果';
 
 CREATE TABLE IF NOT EXISTS vivo_media_callbacks (

+ 2 - 1
src/main/resources/schema.sql

@@ -39,7 +39,8 @@ CREATE TABLE IF NOT EXISTS tencent_tracking_reports (
     status INT NOT NULL COMMENT 'HTTP响应状态码',
     ok TINYINT(1) NOT NULL COMMENT '是否成功(1=成功,0=失败)',
     created_at TIMESTAMP(3) NOT NULL COMMENT '创建时间',
-    KEY idx_tencent_tracking_reports_qk_kind_created_at (qk, kind, created_at)
+    KEY idx_tencent_tracking_reports_qk_kind_created_at (qk, kind, created_at),
+    KEY idx_tencent_tracking_reports_created_at_id (created_at, id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='曝光/点击上报结果';
 
 -- ------------------------------------------------------------