簡體   English   中英

MySQL:按查詢分組

[英]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; 

我認為內部聯接是一種過大的手段,可以用更優化/更高效的查詢代替。 我已經寫了用下面的查詢wheregroup 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.

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