簡體   English   中英

MySQL:優化格式化日期的左連接

[英]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_datedate部分

...
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

如果是這樣,您的問題有一個可行的解決方案:

  1. 在您的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);
  2. 然后在另一個表中創建一個虛擬列(將格式精美的日期塞入您的 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.

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