您好,我將問題說明如下:
(1) 資料庫版本 : MySQL 8.0.23
(2) 資料表 名稱 : TB_202104
這個資料表用來儲存 2021-04-01 00:00:00 到 2021-04-30 23:59:59 這一段期間的資料,有 99200872 筆資料
資料表結構如下 :
`---
CREATE TABLE TB_202104 (
OID INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
ChannelOID INT(10) UNSIGNED NOT NULL,
Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
Value DOUBLE NOT NULL,
LastUpdate TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (OID,Timestamp) USING BTREE,
INDEX IDX_ChaOID(ChannelOID) USING BTREE,
INDEX IDX_ChaOID_Timsta(ChannelOID, Timestamp) USING BTREE,
INDEX IDX_Timsta (Timestamp) USING BTREE
)
COMMENT='儲存 2021/04 感測器資料'
COLLATE='utf8_unicode_ci'
PARTITION BY RANGE (unix_timestamp(`Timestamp`))
(PARTITION p0 VALUES LESS THAN (1617840000) ENGINE = InnoDB,
PARTITION p1 VALUES LESS THAN (1618444800) ENGINE = InnoDB,
PARTITION p2 VALUES LESS THAN (1619049600) ENGINE = InnoDB,
PARTITION p3 VALUES LESS THAN (1619827200) ENGINE = InnoDB,
PARTITION pMax VALUES LESS THAN MAXVALUE ENGINE = InnoDB
);
---`
(3) Function 名稱 : GetMyStartDateTime
Function 結構如下:
`-----------------------------------
CREATE FUNCTION GetMyStartDateTime()
RETURNS timestamp
LANGUAGE SQL
NOT DETERMINISTIC
NO SQL
SQL SECURITY DEFINER
COMMENT '取得 自訂 開始日期時間'
BEGIN
RETURN '2021-05-01 00:00:00';
END
------------------------------------`
(4) View 表名稱 : DynamicTB
這個 View 表的用途是,呼叫 GetMyStartDateTime() , 過濾 Timestamp 欄位 的日期時間資料
View 表結構如下 :
ALTER ALGORITHM = UNDEFINED SQL SECURITY DEFINER VIEW `DynamicTB`
AS
select ChannelOID AS ChannelOID,
Timestamp AS Timestamp,
Value AS VALUE
from TB_202104
where (Timestamp >= GetMyStartDateTime())
limit 1 ;
(5) 當我執行以下指令,執行的時間變得異常的漫長,也沒有執行完成
SELECT * FROM DynamicTB
問題是 DynamicTB 這個View 表 裡搜尋的 TB_202104 資料表根本沒有 在 2021-05-01 00:00:00 的資料。
(6) 但是如果我先把 DynamicTB 如下 :
ALTER ALGORITHM = UNDEFINED SQL SECURITY DEFINER VIEW `DynamicTB`
AS
select ChannelOID AS ChannelOID,
Timestamp AS Timestamp,
Value AS VALUE
from TB_202104 where (Timestamp >= '2021-05-01 00:00:00')
limit 1 ;
然後執行 :
SELECT * FROM DynamicTB
執行不到 一秒就完成了,因為 TB_202104 根本就沒有 2021-05-01 00:00:00 開始及之後的時間資料。
(7) 目前感覺問題在於 在 DynamicTB 這個 View 表中,只要是呼叫 GetMyStartDateTime() 這個 Function 就會變成異常的慢,甚至根本無法執行完成。
GetMyStartDateTime() 也只是回傳 '2021-05-01 00:00:00' 這個值而已,為何 在 DynamicTB 這個 View 表中呼叫 GetMyStartDateTime() 取得相同的值
就有執行異常的問題?
感謝回覆。
雖然你的函數內是 RETURN '2021-05-01 00:00:00';
對你來說是固定常數,但是對 MySQL 優化器來說, 在
where (Timestamp >= '2021-05-01 00:00:00') 與
where (Timestamp >= GetMyStartDateTime()) 兩者意義不同.
一個是明確的常數不變,另一個是函數,函數就有可能變化,優化器無從得知函數是否回應常數.
所以執行時,必須每一筆都對此函數進行評估,執行一次,自然就變慢了.
建議可以改用另一個table, 只放一筆資料,來達到同樣的效果.
或是改寫成
from TB_202104
, (select startts from GetMyStartDateTime()) a
where Timestamp >= startts
這樣也許會有幫助,這段我沒有做測試. 只是初步的一個想法.你參考看看.
用 view 要小心,效率的確是一大障礙,
早期,我也貪圖 view 的方便,建了數百個 view
目前,幾乎不用它了,改用 stored procedure 啦。