簡體   English   中英

MySQL查詢優化:如何加快查詢速度?

[英]MySQL query optimization: how can I speed up this query?

這是我的桌子:

  CREATE TABLE `tab_adasf` (
  `adasf_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `adasf_shopId` int(10) unsigned NOT NULL,
  `adasf_localId` bigint(20) unsigned NOT NULL,
  `adasf_shopState` varchar(255) DEFAULT NULL,
  `adasf_shopCity` varchar(255) DEFAULT NULL,
  `adasf_shopName` varchar(255) DEFAULT NULL,
  `adasf_shopDoor` varchar(255) DEFAULT NULL,
  `adasf_computerName` varchar(255) DEFAULT NULL,
  `adasf_channel` bigint(20) NOT NULL,
  `adasf_totalInside` bigint(20) NOT NULL,
  `adasf_totalOutside` bigint(20) NOT NULL,
  `adasf_createdAt` datetime NOT NULL,
  PRIMARY KEY (`adasf_id`),
  KEY `adasf_shopId` (`adasf_shopId`),
  KEY `adasf_localId` (`adasf_localId`),
  KEY `adasf_shopState` (`adasf_shopState`,`adasf_shopCity`,`adasf_shopName`,`adasf_shopDoor`),
  KEY `adasf_computerName` (`adasf_computerName`,`adasf_channel`,`adasf_createdAt`),
  CONSTRAINT `tab_adasf_ibfk_1` FOREIGN KEY (`adasf_shopId`) REFERENCES `tab_shop` (`shop_id`) ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1453500 DEFAULT CHARSET=utf8

如AUTO_INCREMENT的值所述:它具有1453500行。

為了生成XML文件,我需要如下結果集:

SELECT
    UPPER(adasf_shopState) AS adasf_shopState,
    UPPER(adasf_shopCity) AS adasf_shopCity,
    UPPER(adasf_shopName) AS adasf_shopName,
    UPPER(adasf_shopDoor) AS adasf_shopDoor,
    adasf_computerName,
    adasf_channel,
    SUM(adasf_totalInside) AS adasf_totalInside,
    SUM(adasf_totalOutside) AS adasf_totalOutside,
    YEAR(adasf_createdAt) AS year,
    MONTH(adasf_createdAt) AS month,
    DAY(adasf_createdAt) AS day,
    HOUR(adasf_createdAt) AS hour
    FROM tab_adasf 
WHERE 1=1 AND adasf_shopId = '1' AND HOUR(adasf_createdAt) BETWEEN '10:00' AND '21:00' 
GROUP BY
    UPPER(adasf_shopState),
    UPPER(adasf_shopCity),
    UPPER(adasf_shopName),
    UPPER(adasf_shopDoor),
    adasf_computerName,
    adasf_channel,
    YEAR(adasf_createdAt),
    MONTH(adasf_createdAt),
    DAY(adasf_createdAt),
    HOUR(adasf_createdAt)
ORDER BY
    UPPER(adasf_shopState),
    UPPER(adasf_shopCity),
    UPPER(adasf_shopName),
    UPPER(adasf_shopDoor),
    UPPER(adasf_computerName),
    adasf_channel,
    adasf_createdAt

運行和獲取需要3分鍾。

我的問題是:我在做什么錯? 如何加快此查詢或表的速度?

提前致謝!

為了加快查詢速度,您可以在tab_adasf(adasf_shopId)上創建索引。 如果您有很多商店,這應該對性能有很大幫助。

如果您需要進行大量此類查詢,請考慮將adasf_createdAt列拆分為日期部分和時間部分。 然后,您可以在tab_adasf(adasf_shopId, adasf_createdAt_time)上創建索引tab_adasf(adasf_shopId, adasf_createdAt_time)進一步幫助查詢。

通常,除非您有充分的理由,否則不建議將時間與日期時間分開。 這類查詢的性能提高構成了“充分的理由”。

正如其他人所說,這種查詢整個表的報表本質上是耗時的。 話雖如此,這是一個或兩個建議。

首先,消除GROUP BY子句中的UPPER()函數調用。 無論如何,MySQL的排序規則都不區分大小寫。

其次,嘗試在GROUP BY中使用此表達式,而不是GROUP BY年,月,日,小時。

 DATE_FORMAT(adasf_createdAt, '%Y-%m-%d %H:00:00')

這基本上會將您的createdAt值四舍五入到前一個小時。

第三,讓我們重構讀取的WHERE項目

 HOUR(adasf_createdAt) BETWEEN '10:00' AND '21:00'

應該說

 HOUR(adasf_createdAt) BETWEEN 10 AND 21

而且,如果您從主查詢中刪除該記錄,則會加快速度。 然后,您可以將查詢包裝在另一個查詢中,如下所示:

SELECT *
  FROM ( /*your whole query without the WHERE HOUR() BETWEEN clause */
       ) AS q
  WHERE q.hour BETWEEN 10 AND 21

最后,嘗試在

 adasf_shopId, adasf_shopState, adasf_shopCity, adasf_shopName, adasf_shopDoor,
 adasf_computerName, adasf_channel,  adasf_CreatedAt, 
 adasf_totalInside, adasf_totalOutside

該索引具有滿足您的查詢所需的所有信息,這些信息按順序排列。 這可能會加快您的查詢速度。

因此,您的最終查詢如下所示:

SELECT *
  FROM (
SELECT
       UPPER(adasf_shopState) AS adasf_shopState,
       UPPER(adasf_shopCity) AS adasf_shopCity,
       UPPER(adasf_shopName) AS adasf_shopName,
       UPPER(adasf_shopDoor) AS adasf_shopDoor,
       adasf_computerName,
       adasf_channel,
       SUM(adasf_totalInside) AS adasf_totalInside,
       SUM(adasf_totalOutside) AS adasf_totalOutside,
       YEAR(adasf_createdAt) AS year,
       MONTH(adasf_createdAt) AS month,
       DAY(adasf_createdAt) AS day,
       HOUR(adasf_createdAt) AS hour
 FROM tab_adasf 
WHERE 1=1 
  AND adasf_shopId = '1'  
GROUP BY
      adasf_shopState,
      adasf_shopCity,
      adasf_shopName,
      adasf_shopDoor,
      adasf_computerName,
      adasf_channel, 
      DATE_FORMAT(adasf_createdAt, '%Y-%m-%d %H:00:00')
ORDER BY
      adasf_shopState,
      adasf_shopCity,
      adasf_shopName,
      adasf_shopDoor,
      adasf_computerName,
      adasf_channel, 
      DATE_FORMAT(adasf_createdAt, '%Y-%m-%d %H:00:00')
     ) AS q
  WHERE q.hour BETWEEN 10 AND 21

對查詢的這種簡化加上覆蓋索引可能會使查詢更快。

請注意,我尚未調試此查詢,也沒有調試數據。

編輯:這個答案在MySQL中不起作用。

您必須使用全表掃描來檢查每一行,以查看它是否與HOUR(adasf_createdAt) BETWEEN '10:00' AND '21:00'相匹配。

HOUR(adasf_createdAt)上創建功能索引。

另外,有關如何有效使用索引的出色教程,請參見http://use-the-index-luke.com

暫無
暫無

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

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