MySQL | 辛比記 https://tec.xenby.com 實作與技術探討 Sun, 07 Aug 2022 05:32:37 +0000 zh-TW hourly 1 https://wordpress.org/?v=6.0.9 https://tec.xenby.com/wp-content/uploads/2020/07/icon_src2.png MySQL | 辛比記 https://tec.xenby.com 32 32 180727598 MySQL 組合型 index 查詢技巧 https://tec.xenby.com/40-mysql-%e7%b5%84%e5%90%88%e5%9e%8b-index-%e6%9f%a5%e8%a9%a2%e6%8a%80%e5%b7%a7 https://tec.xenby.com/40-mysql-%e7%b5%84%e5%90%88%e5%9e%8b-index-%e6%9f%a5%e8%a9%a2%e6%8a%80%e5%b7%a7#respond Tue, 21 Jul 2020 15:13:16 +0000 https://tec.xenby.com/?p=40 前一篇已講解如何設計 index,本篇將介紹如何知道目前使用... Read more »

MySQL 組合型 index 查詢技巧〉這篇文章最早發佈於《辛比記》。]]>

前一篇已講解如何設計 index,本篇將介紹如何知道目前使用的 SQL 用到了哪個 index 以及在有 index 的情況下如何使用有效使用 index。

範例 schema

這邊使用一個範例是電商的商品,資料庫存了商品的名稱、條碼種類、條碼值以及價格,並且有兩個 index 分別用來查詢條碼以及價格。

CREATE TABLE `item` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(100) NOT NULL COMMENT '商品名稱',
  `code_type` varchar(5) NOT NULL COMMENT '條碼種類',
  `code_value` varchar(20) NOT NULL COMMENT '條碼數值',
  `price` varchar(45) NOT NULL COMMENT '價格',
  PRIMARY KEY (`id`),
  KEY `__code_type__code_value__index` (`code_type`,`code_value`),
  KEY `__price` (`price`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

MySQL 如何知道 Query 的 SQL 使用了哪個 index

假設我們進行複雜 SQL 查詢時,不確定會不會使用 index 的時候,或是想知道是使用哪一組 index 時,可以在輸入的 SQL 前面加上 desc 進行查詢,便會顯示查詢可能會使用的 index

以上這個 SQL 顯示 possible_keys 是 null,表示查詢並沒有使用 index , rows 表示會需要檢索過多少筆才能找到資料。

而上面這個 SQL 則顯示會使用 __code_type__code_value__index 這個 index 來進行查詢,而 rows 為 1 只需檢索一筆資料就能找到結果。

※ 對於資料庫效能考量,rows 這個值是越小越好,表示經過 index 濾出後不需要對太多筆資料進行值的比對。

有效使用 index

原本的情境是假設查詢 code_value 時一定會給對應的 code_type 一起查詢,但是假如今天遇到一個臨時狀況是有人只有提供條碼為 7977761108033,但是 code_type 已經遺失了不確定是什麼,那這種時候要如何處理呢?

直覺可能會直接使用一個 SQL 查詢:

select * from item where code_value = '7977761108033';

這邊在一個資料筆數 500 多萬筆可以看到查詢時間花費了 2.33 秒,是因為沒有使用到 index,可能不會覺得太久,但是如果資料量到達上億的時候,這時間可能就會超過幾分鐘了,且不會因為這個臨時需求增加 index,因為對於資料量達上億筆的 table alter 可能需要執行好幾個小時,所需要的成本太高了。

那這邊要怎樣解決這個問題呢?

我們可以先窮舉出所有 code_type 後,再搭配一起查詢 code_value 這樣就能使用到 index。

select distinct code_type from item;

因為有 __code_type__code_value__index 這個 index 的關係,在進行窮舉的時候速度非常快,接著可以將所有的 type 使用 where in 方式搭配進去查詢

select * from item where code_value = '7977761108033' and code_type in ('Code39', 'EAN', 'SKU', 'UPC');

由這邊可以看出,雖然我們多使用了一個 SQL 來查詢,但是整體時間卻大幅度的提升了。

MySQL 組合型 index 查詢技巧〉這篇文章最早發佈於《辛比記》。]]>
https://tec.xenby.com/40-mysql-%e7%b5%84%e5%90%88%e5%9e%8b-index-%e6%9f%a5%e8%a9%a2%e6%8a%80%e5%b7%a7/feed 0 40
MySQL 基礎索引設計與選擇 https://tec.xenby.com/38-mysql-%e5%9f%ba%e7%a4%8e%e7%b4%a2%e5%bc%95%e8%a8%ad%e8%a8%88%e8%88%87%e9%81%b8%e6%93%87 https://tec.xenby.com/38-mysql-%e5%9f%ba%e7%a4%8e%e7%b4%a2%e5%bc%95%e8%a8%ad%e8%a8%88%e8%88%87%e9%81%b8%e6%93%87#respond Tue, 14 Jul 2020 00:47:02 +0000 https://tec.xenby.com/?p=38 對於關聯式資料庫來說,index (索引) 是一個很重要的東... Read more »

MySQL 基礎索引設計與選擇〉這篇文章最早發佈於《辛比記》。]]>

對於關聯式資料庫來說,index (索引) 是一個很重要的東西,如果欄位有 index 的話在查詢速度會很快,如果沒有設計 index 就會需要 scan table,但是加上 index 並不是無成本的,首先 index 需要有空間進行儲存,多餘的 index 會浪費儲存空間,多個索引甚至可能比 table 還大,另外 MySQL 中是使用 B+Tree 進行索引,在 insert 資料時會需要更新樹的結構,當 index 太多的時候就會需要重整太多的樹會消費比較多的時間,本篇介紹可以如何設計 index。

索引的設計

假設現在有個書店,儲存書本的表格如下:

CREATE TABLE `book` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(200) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '書名',
  `isbn` varchar(15) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '統一商品編碼',
  `price` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '價格',
  `language` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '內文語言',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

這邊以這個 table 當作範例

依照使用需求加上索引 – 單一索引

假如現在電商的功能是以價格範圍進行搜尋,查詢的 SQL 如下:

SELECT * FROM book WHERE price >= ? AND price <= ?;

因為 WHERE 條件查詢只有一個欄位,所以這很簡單那索引 (price)

ALTER TABLE `book` 
ADD INDEX `__index__price` (`price`);

依照使用需求加上索引 – 組合索引

而假如現在有情境變成搜尋價格指定語言的書本

SELECT * FROM book WHERE price >= ? AND price <= ? AND language = ?;

這時條件式有兩個欄位,多了 language 這個欄位,這時不能只加一個 index (language),因為在同一張 table 中, simple query 只為選擇使用一個 index 來查詢

所以要弄一個組合式 index (price, language) 或 (language, price),而有兩種組合哪一種比較好呢? 答案是選擇分類比較少的放前面會比較快,例如這邊語系實際上只有約兩百個值,而 price 是數字值比較多變化,所以這邊要選擇 (language, price)

來比較一下單一索引與組合型索引的速度差異

下圖為 (price) + (language) 兩個索引的查詢速度 (0.89 秒)

下圖為 (price, language) 一個索引的查詢速度 (0.42 秒)

下圖為 (language, price) 一個索引的查詢速度 (0.02 秒)

MySQL 基礎索引設計與選擇〉這篇文章最早發佈於《辛比記》。]]>
https://tec.xenby.com/38-mysql-%e5%9f%ba%e7%a4%8e%e7%b4%a2%e5%bc%95%e8%a8%ad%e8%a8%88%e8%88%87%e9%81%b8%e6%93%87/feed 0 38