簡體   English   中英

使用“group by”鍵中的函數優化查詢?

[英]Optimize query with functions in `group by` key?

我正在使用 MySQL 8.0 並且在要優化的大表上有一個緩慢的查詢。

該表包含1100 萬行數據及其結構:

CREATE TABLE `ccu` (
  `id` bigint NOT NULL,
  `app_id` int NOT NULL,
  `ccu` int NOT NULL,
  `audit_create` datetime NOT NULL,
  PRIMARY KEY (`id`) USING BTREE,
  UNIQUE KEY `ccu_game_create_time_2a10bc69_idx` (`app_id`,`audit_create`) USING BTREE,
  KEY `ccu_audit_create_idx` (`audit_create`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci

我的查詢是:

SELECT app_id, DATE(audit_create) cal_day, MAX(ccu) pcu, ROUND(AVG(ccu)) id_acu 
FROM ccu
WHERE audit_create BETWEEN DATE_SUB(DATE(NOW()), INTERVAL 29 DAY) AND DATE(NOW())
GROUP BY app_id, DATE(audit_create)

查詢運行超過 2 秒。 我通過between... and...添加條件來過濾有用的數據。 但是,存儲在audit_create中的數據格式為yyyy-MM-dd HH:mm:ss ,我必須使用date function 但根據執行計划只有where條件使用索引(仍然有臨時表), group by子句根本不使用任何索引。 在此處輸入圖像描述

我無權更改表結構以添加日期列。 是否可以優化查詢以降低查詢時間?

我能夠通過添加表達式索引來消除Using temporary

mysql> alter table ccu add key bk1 (app_id, (cast(audit_create as date)));
Query OK, 0 rows affected (0.02 sec)
Records: 0  Duplicates: 0  Warnings: 0

mysql> explain SELECT app_id, DATE(audit_create) cal_day, 
   MAX(ccu) pcu, ROUND(AVG(ccu)) id_acu  
 FROM ccu 
 WHERE date(audit_create) BETWEEN DATE_SUB(DATE(NOW()), INTERVAL 29 DAY) AND DATE(NOW()) 
 GROUP BY app_id, cast(audit_create as date)\G 
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: ccu
   partitions: NULL
         type: index
possible_keys: bk1
          key: bk1
      key_len: 8
          ref: NULL
         rows: 1
     filtered: 100.00
        Extra: Using where

不幸的是,EXPLAIN 報告顯示它將使用type: index這是一個索引掃描,換句話說它將檢查 1100 萬個索引條目中的每一個。 它可能會使它比您的查詢更糟

我唯一的其他建議是每天運行一次此查詢並將結果存儲在匯總表中。 每天運行一次 2 秒的查詢以便快速獲得聚合結果應該是可以接受的。 但是你說你沒有添加列的權限,所以我猜你也沒有添加表的權限。

在這種情況下,買一台速度更快、內存更大的電腦。

微不足道的改進: DATE(NOW()) --> CURDATE()

主要改進:

擺脫id並改變

PRIMARY KEY (`id`) USING BTREE,
UNIQUE KEY `ccu_game_create_time_2a10bc69_idx` (`app_id`,`audit_create`) USING BTREE,

只是

PRIMARY KEY (`app_id`,`audit_create`),

這避免了對每一行進行二次查找。

在 29 天的范圍內似乎有 240 萬行(共 1100 萬行)。 優化器必須決定是否使用索引(它確實這樣做了),但要承受 240 萬次額外查找,而不是掃描所有 1100 萬行,從而需要額外排序。

另一件要檢查的事情是innodb_buffer_pool_size 如果表太大以至於無法放入該緩存,則可能有大量 I/O。 (同樣,我的索引更改將對此有所幫助。)

是的,Bill 生成的列可能會增加更多的性能,這與我的建議無關。

警告:
您的范圍是 29 天 + 1 秒。
Bill 的范圍是 30 天。

無論audit_create的數據類型如何,這都可以在今天早上之前得到恰好 29 天:

WHERE audit_create >= CURDATE() - INTERVAL 29 DAY
  AND audit_create  < CURDATE()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM