[英]MySQL: Optimize left join on formatted date
我正在嘗試優化此查詢的速度:
SELECT t.t_date td, v.visit_date vd
FROM temp_dates t
LEFT JOIN visits v ON DATE_FORMAT(v.visit_date, '%Y-%m-%d') = t.t_date
ORDER BY t.t_date
v.visit_date 是 DATETIME 類型,t.t_date 是格式為 '%Y-%m-%d' 的字符串。 簡單地在 v.visitdate 上創建索引並沒有提高速度。 因此我打算嘗試@oysteing 在這里給出的解決方案: How to optimize mysql group by with DATE_FORMAT我通過這個 SQL ALTER TABLE visits ADD COLUMN datestr varchar(10) AS (DATE_FORMAT(visit_date, '%Y-%m-%d')) VIRTUAL;
但是,當我嘗試通過CREATE INDEX idx_visit_date on visits(datestr)
在此列上創建索引時,我收到此錯誤:
#1901 - Function 或表達式 'date_format()' 不能在
datestr
的 GENERATED ALWAYS AS 子句中使用
我究竟做錯了什么? 我的數據庫是 Maria DB 10.4.8
最好的問候 - 烏爾里希
date_format()
也不能用於持久生成的列。 而且在索引中它不能只是虛擬的,它必須被持久化。
我在手冊中找不到明確的聲明,但我相信這是因為date_format()
的 output 可能取決於語言環境,因此不是嚴格確定的。
您可以使用諸如concat()
、 year()
、 month()
、 day()
和lpad()
等確定性函數來構建字符串,而不是date_format()
)。
...
datestr varchar(10) AS (concat(year(visit_date),
'-',
lpad(month(visit_date), 2, '0'),
'-',
lpad(day(visit_date), 2, '0')))
...
但正如我在評論中已經提到的那樣,你正在修復錯誤的結局。 日期/時間不應存儲為字符串。 因此,您應該將temp_dates.t_date
提升為date
並使用date()
在生成的索引列中提取visit_date
的date
部分
...
visit_date_date date AS (date(visit_date))
...
您可能還想嘗試索引temp_dates.t_date
。
這對你有用嗎?
SELECT t.t_date td, v.visit_date vd
FROM temp_dates t
LEFT JOIN visits v ON DATE(v.visit_date) = DATE(t.t_date)
ORDER BY t.t_date
如果是這樣,您的問題有一個可行的解決方案:
在您的visit_date
object 上使用確定性DATE()
function 添加一個DATE
列。 像這樣。
ALTER TABLE visits ADD COLUMN dateval DATE AS (DATE(visit_date)) VIRTUAL; CREATE INDEX idx_visit_date on visits(dateval);
然后在另一個表中創建一個虛擬列(將格式精美的日期塞入您的 VARCHAR() 列中的那個。
ALTER TABLE temp_dates ADD COLUMN dateval DATE AS (DATE(t_date)) VIRTUAL; CREATE INDEX idx_temp_dates_date on temp_dates (dateval);
這是有效的,因為DATE()
是確定性的,不像DATE_FORMAT()
。
那么你的查詢應該是。
SELECT t.t_date td, v.visit_date vd
FROM temp_dates t
LEFT JOIN visits v ON v.dateval = t.dateval
ORDER BY t.t_date
此解決方案為您提供(虛擬) DATE
列的索引。 這很好,因為此類列上的索引匹配是有效的。
但是,您最好的解決方案是將temp_date.t_date
的數據類型從VARCHAR()
更改為DATE
。
DATE_FORMAT(expr, format)
不能用於虛擬列,因為它取決於連接的語言環境(MariaDB 問題MDEV-11553 )。
為添加語言環境的date_format創建了一個 3 參數形式。
DATE_FORMAT(visit_date, '%Y-%m-%d', 'en_US')
可以在 MariaDB-10.3+ 穩定版本的虛擬列表達式中使用。
絕對建議使用DATE
或更改查詢以不使用列表達式周圍的函數。
函數不是“可存儲的”。
考慮:
ON v.visit_date >= t.t_date
AND v.visit_date < t.t_date + INTERVAL 1 DAY
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.