[英]MySQL: Group by query optimization
我有以下模式的表:
+----+--------+----------------------------+----------------------------+
| id | amount | created_timestamp | updated_timestamp |
+----+--------+----------------------------+----------------------------+
| 1 | 1.00 | 2018-01-09 12:42:38.973222 | 2018-01-09 12:42:38.973222 |
+----+--------+----------------------------+----------------------------+
在這里,對於id = 1
,可能會有多個金額條目。 我想提取最后添加的條目及其對應的數量(按ID分組)。
我在self表上編寫了一個帶有內部聯接的工作查詢,如下所示:
SELECT t1.id,
t1.amount,
t1.created_timestamp,
t1.updated_timestamp
FROM transactions AS t1
INNER JOIN (SELECT id,
Max(updated_timestamp) AS last_transaction_time
FROM transactions
GROUP BY id) AS latest_transactions
ON latest_transactions.id = t1.id
AND latest_transactions.last_transaction_time =
t1.updated_timestamp;
我認為內部聯接是一種過大的手段,可以用更優化/更高效的查詢代替。 我已經寫了用下面的查詢where
, group by
,並且having
,但它是不工作。 有人可以幫忙嗎?
select id, any_value(`updated_timestamp`), any_value(amount) from transactions group by `id` having max(`updated_timestamp`);
在MySQL中執行這樣的查詢時,有兩個(好的)選項。 您已經嘗試了一種選擇。 這是另一個:
SELECT t1.id,
t1.amount,
t1.created_timestamp,
t1.updated_timestamp
FROM transactions AS t1
LEFT OUTER JOIN transactions later_transactions
ON later_transactions.id = t1.id
AND later_transactions.last_transaction_time > t1.updated_timestamp
WHERE later_transactions.id IS NULL
這些方法是文檔中的方法 ,也是我基本上每天在工作中使用的方法。 哪個效率最高取決於多種因素,但是通常情況下,如果一個速度較慢,則另一個速度較快。
另外,正如Strawberry在評論中指出的那樣,您需要在(id,updated_timestamp)
上有一個復合索引。 具有單獨的id
索引, updated_timestamp
不相等。
請注意,索引只是表中數據的副本。 在許多方面,它的作用與表相同。 因此,創建索引就是創建表數據的副本,RDBMS可以使用該副本以更有效的方式查詢表信息。
剛在updated_timestamp
創建的索引將創建包含updated_timestamp
作為第一列的數據的副本,並將對該數據進行排序。 它還將在每個這些索引行中包含一個隱藏的行ID值(將用作主鍵),以便可以使用它在實際表中查找完整的行。
這對查詢(兩個版本)有何幫助? 如果我們只想要最新的(或最早的) updated_timestamp
,這將有所幫助,因為它可以檢查索引中的第一條或最后一條記錄。 但是因為我們想要每個id
的最新值,所以該索引沒有用。
那只是id
的索引呢? 在這里,我們有副本id
列,通過排序id
列,以連接到索引中的每一行的行ID。
這對查詢有何幫助? 事實並非如此,因為它甚至沒有updated_timestamp
列作為索引的一部分,因此甚至不考慮使用此索引。
現在,考慮一個復合索引: (id,updated_timestamp)
。
這將創建一個數據副本,其id
列首先進行排序,然后再包含第二列updated_timestamp
,並且還將在每個id
內對其進行排序。
這與電話簿(如果人們仍然使用這些東西而不是紙鎮)的方式相同,是按姓氏,然后按名字排序。
因為以這種方式對行進行了排序,所以MySQL可以針對每個id
查找給定id
的最后一條記錄。 它知道該記錄包含最高的updated_timestamp
值,這是因為索引的定義方式。
因此,它只需要為存在的每個id
查找一行即可。 那太快了。 進一步解釋為什么會占用更多空間,但是您可以根據需要自己研究,只需查看B樹即可。 只需說一下,找到第一個(或最后一個)記錄就很容易了。
請嘗試以下操作:
ALTER TABLE transactions
ADD INDEX `LatestTransaction` (`id`,`updated_timestamp`)
然后查看您的原始查詢還是我的備用查詢更快。 可能兩者都比沒有索引要快。 隨着表的增長或select語句的更改,它可能會影響這些查詢中的哪些查詢更快,但是無論使用哪個版本的查詢,索引都將提供最大的性能提升。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.