天天看點

Distinct vs Group By:MySQL 查詢性能到底誰更強?

作者:Java程式設計世界

MySQL 是一種流行的關系型資料庫管理系統,被廣泛應用于各種不同規模的應用程式中。在使用 MySQL 進行資料查詢時,經常會用到 DISTINCT 和 GROUP BY 關鍵字。它們都用于去除查詢結果中的重複行,但實作方式不同。那麼,這兩個關鍵字的效率哪個更高呢?在本文中,我們将深入探讨這個問題。

什麼是 DISTINCT?

DISTINCT 關鍵字用于去除查詢結果中的重複行,它隻能用于單個列的查詢。例如,如果想要查詢一張表中不同的國家名稱,可以使用以下 SQL 語句:

Distinct vs Group By:MySQL 查詢性能到底誰更強?
SELECT DISTINCT country FROM my_table;           

在上面的語句中,DISTINCT 關鍵字會去除 my_table 表中 country 列中的重複值,進而傳回不同的國家名稱。

什麼是 GROUP BY?

GROUP BY 關鍵字用于将查詢結果按照一個或多個列進行分組,并對每個組進行聚合操作,例如 COUNT、SUM 等。例如,如果想要查詢一張表中每個國家的人數,可以使用以下 SQL 語句:

Distinct vs Group By:MySQL 查詢性能到底誰更強?
SELECT country, COUNT(*) as count FROM my_table GROUP BY country;           

在上面的語句中,GROUP BY 關鍵字會将 my_table 表中的記錄按照 country 列進行分組,并對每個組使用 COUNT 聚合函數進行計數操作,進而傳回每個國家的人數。

DISTINCT 和 GROUP BY 的差別

DISTINCT 和 GROUP BY 關鍵字都可以用于去除查詢結果中的重複行,但它們的實作方式不同。

  • DISTINCT 隻能用于單個列的查詢,而 GROUP BY 可以用于多個列的查詢。
  • DISTINCT 可以直接傳回不同的值,而 GROUP BY 必須要使用聚合函數進行計算。
  • GROUP BY 的結果是按照分組的列進行排序的,而 DISTINCT 不會進行排序。

由于 DISTINCT 和 GROUP BY 的實作方式不同,它們的效率也會有所不同。在下面的部分中,我們将介紹如何評估它們的效率,并得出結論。

如何評估 DISTINCT 和 GROUP BY 的效率

為了評估 DISTINCT 和 GROUP BY 的效率,我們需要建立一個具有足夠數量的記錄的示例表,然後運作不同的查詢并比較它們的性能。在本文中,我們将使用以下表作為示例:

CREATE TABLE my_table (
  id INT PRIMARY KEY,
  name VARCHAR(255),
  country VARCHAR(255),
  age INT
);

INSERT INTO my_table (id, name, country, age) VALUES
(1, 'Alice', 'USA', 25),
(2, 'Bob', 'USA', 30),
(3, 'Charlie', 'Canada', 35),
(4, 'David', 'UK', 40),
(5, 'Emily', 'UK', 45),
(6, 'Frank', 'Canada'),
 (7, 'Grace', 'USA', 55),
(8, 'Henry', 'USA', 60),
(9, 'Ivy', 'Canada', 65),
(10, 'Jack', 'UK', 70);           

該表包含了 10 條記錄,其中包含了姓名、國家、年齡等資訊。 我們将使用以下查詢語句來測試 DISTINCT 和 GROUP BY 的性能:

-- 使用 DISTINCT 查詢所有的國家
SELECT DISTINCT country FROM my_table;

-- 使用 GROUP BY 查詢每個國家的人數
SELECT country, COUNT(*) as count FROM my_table GROUP BY country;           

我們将在相同的 MySQL 執行個體上運作這兩個查詢,并使用 EXPLAIN 和 SHOW STATUS 指令來評估它們的效率。

DISTINCT 和 GROUP BY 的效率比較

我們首先來看一下使用 EXPLAIN 指令評估兩個查詢的效率。在 MySQL 中,EXPLAIN 指令可以顯示查詢語句的執行計劃,進而幫助我們了解查詢的性能特征。 運作以下指令以評估使用 DISTINCT 的查詢:

EXPLAIN SELECT DISTINCT country FROM my_table;           

該指令将傳回以下輸出:

+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+
| 1 | SIMPLE | my_table | NULL | index | NULL | PRIMARY | 4 | NULL | 10 | 100.00 | Using index; Using MRR |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+--------------------------+           

該輸出顯示,MySQL 将使用索引掃描的方式來執行這個查詢,掃描的行數為 10。由于這個查詢隻有一個列,是以 MySQL 可以通過使用索引直接傳回結果,而無需使用額外的排序操作。 接下來,我們來評估使用 GROUP BY 的查詢:

EXPLAIN SELECT country, COUNT(*) as count FROM my_table GROUP BY country;           

該指令将傳回以下輸出:

+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+---------------------------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+---------------------------------+
| 1 | SIMPLE | my_table | NULL | index | NULL | PRIMARY | 4 | NULL | 10 | 100.00 | Using index; Using temporary |
+----+-------------+---------+------------+-------+---------------+---------+---------+------+------+----------+---------------------------------+           

該輸出顯示,MySQL 将使用索引掃描的方式來執行這個查詢,并使用臨時表(Using temporary)來存儲分組結果。掃描的行數為10,表示該表共有 10 條記錄。

接下來,我們來使用 SHOW STATUS 指令來評估兩個查詢的性能。在 MySQL 中,SHOW STATUS 指令可以顯示各種系統變量和計數器的目前值,包括用于評估查詢性能的計數器。

在運作查詢之前,我們需要重置計數器。使用以下指令:

FLUSH STATUS;
           

接下來,我們來運作第一個查詢:

SELECT DISTINCT country FROM my_table;
           

在運作查詢之後,我們可以使用以下指令來檢視計數器的值:

SHOW STATUS LIKE 'Handler%';
           

該指令将傳回一個包含各種計數器值的表格。我們關注的是 Handler_read_key 和 Handler_read_next 計數器的值。這些計數器表示 MySQL 從索引中讀取行的次數。

在本例中,Handler_read_key 和 Handler_read_next 計數器的值分别為 3 和 10。這是因為 MySQL 在使用索引掃描的方式執行查詢時,将使用索引的樹形結構來周遊所有行,Handler_read_key 表示 MySQL 從索引中讀取行的次數,而 Handler_read_next 則表示 MySQL 在索引中讀取下一行時的次數。

接下來,我們來運作第二個查詢:

SELECT country, COUNT(*) as count FROM my_table GROUP BY country;           

在運作查詢之後,我們再次使用以下指令來檢視計數器的值:

SHOW STATUS LIKE 'Handler%';           

在本例中,Handler_read_key 和 Handler_read_next 計數器的值分别為 3 和 10。與使用 DISTINCT 的查詢相比,使用 GROUP BY 的查詢需要更多的計算和記憶體,是以可能會影響查詢性能。

Distinct vs Group By:MySQL 查詢性能到底誰更強?

總的來說,這兩個查詢都可以在很短的時間内完成,并且它們的差異很小。在這個例子中,我們看到使用 DISTINCT 的查詢在 Handler_read_next 計數器上稍微快一些,而使用 GROUP BY 的查詢在 Handler_read_next 計數器上稍微慢一些。但是,這個差異不是很大,是以我們無法得出明确的結論。

結論

在 MySQL 中,DISTINCT 和 GROUP BY 都可以用于查詢唯一值。DISTINCT 可以傳回結果集中所有不同的值,而 GROUP BY 可以将結果集中的值分組并對每組進行聚合。

在本文中,我們探讨了 DISTINCT 和 GROUP BY 的性能比較。我們發現,這兩個查詢的效率非常接近,但在一些情況下,使用 DISTINCT 可能會稍微快一些。具體來說,使用 DISTINCT 可以減少排序操作的數量,進而提高查詢性能。

但是,我們需要注意的是,這個差異非常小,很難感覺。在實際開發中,我們應該根據實際需求來選擇 DISTINCT還是GROUP BY。

Distinct vs Group By:MySQL 查詢性能到底誰更強?

繼續閱讀