Christina問我:你都是如何設計索引的?

2021-02-20 掘金開發者社區
前言

資料庫系列更新到現在我想大家對所有的概念都已有個大概認識了,這周我在看評論的時候我發現有個網友的提問我覺得很有意思:帥丙如何設計一個索引?你們都是怎麼設計索引的?怎麼設計更高效?

我一想索引我寫過很多了呀,沒道理讀者還不會啊,但是我一回頭看完,那確實,我就寫了索引的概念,優劣勢,沒提到怎麼設計,那這篇文章又這樣應運而生了。

本文還是會有很多之前寫過的重複概念,但是也是為了大家能更好的理解MySQL中幾種索引設計的原理。

正文

我們知道,索引是一個基於鍊表實現的樹狀Tree結構,能夠快速的檢索數據,目前幾乎所RDBMS資料庫都實現了索引特性,比如MySQL的B+Tree索引,MongoDB的BTree索引等。

在業務開發過程中,索引設計高效與否決定了接口對應SQL的執行效率,高效的索引可以降低接口的Response Time,同時還可以降低成本,我們要現實的目標是:索引設計->降低接口響應時間->降低伺服器配置->降低成本,最終要落實到成本上來,因為老闆最關心的是成本

今天就跟大家聊聊MySQL中的索引以及如何設計索引,使用索引才能提降低接口的RT,提高用戶體檢。

MySQL中的索引

MySQL中的InnoDB引擎使用B+Tree結構來存儲索引,可以儘量減少數據查詢時磁碟IO次數,同時樹的高度直接影響了查詢的性能,一般樹的高度維持在 3~4 層。

B+Tree由三部分組成:根root、枝branch以及Leaf葉子,其中root和branch不存儲數據,只存儲指針地址,數據全部存儲在Leaf Node,同時Leaf Node之間用雙向鍊表連結,結構如下:

從上面可以看到,每個Leaf Node是三部分組成的,即前驅指針p_prev,數據data以及後繼指針p_next,同時數據data是有序的,默認是升序ASC,分布在B+tree右邊的鍵值總是大於左邊的,同時從root到每個Leaf的距離是相等的,也就是訪問任何一個Leaf Node需要的IO是一樣的,即索引樹的高度Level + 1次IO操作。

我們可以將MySQL中的索引可以看成一張小表,佔用磁碟空間,創建索引的過程其實就是按照索引列排序的過程,先在sort_buffer_size進行排序,如果排序的數據量大,sort_buffer_size容量不下,就需要通過臨時文件來排序,最重要的是通過索引可以避免排序操作(distinct,group by,order by)。

聚集索引

MySQL中的表是IOT(Index Organization Table,索引組織表),數據按照主鍵id順序存儲(邏輯上是連續,物理上不連續),而且主鍵id是聚集索引(clustered index),存儲著整行數據,如果沒有顯示的指定主鍵,MySQL會將所有的列組合起來構造一個row_id作為primary key,例如表users(id, user_id, user_name, phone, primary key(id)),id是聚集索引,存儲了id, user_id, user_name, phone整行的數據。

輔助索引

輔助索引也稱為二級索引,索引中除了存儲索引列外,還存儲了主鍵id,對於user_name的索引idx_user_name(user_name)而言,其實等價於idx_user_name(user_name, id),MySQL會自動在輔助索引的最後添加上主鍵id,熟悉Oracle資料庫的都知道,索引裡除了索引列還存儲了row_id(代表數據的物理位置,由四部分組成:對象編號+數據文件號+數據塊號+數據行號),我們在創建輔助索引也可以顯示添加主鍵id。

-- 創建user_name列上的索引
mysql> create index idx_user_name on users(user_name);
-- 顯示添加主鍵id創建索引
mysql> create index idx_user_name_id on users(user_name,id);
-- 對比兩個索引的統計數據
mysql> select a.space as tbl_spaceid, a.table_id, a.name as table_name, row_format, space_type,  b.index_id , b.name as index_name, n_fields, page_no, b.type as index_type  from information_schema.INNODB_TABLES a left join information_schema.INNODB_INDEXES b  on a.table_id =b.table_id where a.name = 'test/users';
+---++--+--+--++---++-
| tbl_spaceid | table_id | table_name | row_format | space_type | index_id | index_name       | n_fields | page_no | index_type |
+---++--+--+--++---++-
|         518 |     1586 | test/users | Dynamic    | Single     |     1254 | PRIMARY          |        9 |       4 |          3 |
|         518 |     1586 | test/users | Dynamic    | Single     |     4003 | idx_user_name    |        2 |       5 |          0 |
|         518 |     1586 | test/users | Dynamic    | Single     |     4004 | idx_user_name_id |        2 |      45 |          0 |
mysql> select index_name, last_update, stat_name, stat_value, stat_description from mysql.innodb_index_stats where index_name in ('idx_user_name','idx_user_name_id');
+---+-+----+--++
| index_name       | last_update         | stat_name    | stat_value | stat_description                  |
+---+-+----+--++   
| idx_user_name    | 2021-01-02 17:14:48 | n_leaf_pages |       1358 | Number of leaf pages in the index |
| idx_user_name    | 2021-01-02 17:14:48 | size         |       1572 | Number of pages in the index      |
| idx_user_name_id | 2021-01-02 17:14:48 | n_leaf_pages |       1358 | Number of leaf pages in the index |
| idx_user_name_id | 2021-01-02 17:14:48 | size         |       1572 | Number of pages in the index      |

對比一下兩個索引的結果,n_fields表示索引中的列數,n_leaf_pages表示索引中的葉子頁數,size表示索引中的總頁數,通過數據比對就可以看到,輔助索引中確實包含了主鍵id,也說明了這兩個索引時完全一致。

Index_namen_fieldsn_leaf_pagessizeidx_user_name213581572idx_user_name_id213581572索引回表

上面證明了輔助索引包含主鍵id,如果通過輔助索引列去過濾數據有可能需要回表,舉個例子:業務需要通過用戶名user_name去查詢用戶表users的信息,業務接口對應的SQL:

select  user_id, user_name, phone from users where user_name = 'Laaa';

我們知道,對於索引idx_user_name而言,其實就是一個小表idx_user_name(user_name, id),如果只查詢索引中的列,只需要掃描索引就能獲取到所需數據,是不需要回表的,如下SQL語句:

SQL 1:  select id, user_name from users where user_name = 'Laaa';

SQL 2:  select id from users where user_name = 'Laaa';

mysql> explain select id, name from users where name = 'Laaa';
+----+---+--+--+-+++----+--+-+--
| id | select_type | table | partitions | type | possible_keys | key           | key_len | ref   | rows | filtered | Extra       |
+----+---+--+--+-+++----+--+-+--
|  1 | SIMPLE      | users | NULL       | ref  | idx_user_name | idx_user_name | 82      | const |    1 |   100.00 | Using index |
mysql> explain select id from users where name = 'Laaa';
+----+---+--+--+-+++----+--+-+--
| id | select_type | table | partitions | type | possible_keys | key           | key_len | ref   | rows | filtered | Extra       |
+----+---+--+--+-+++----+--+-+--
|  1 | SIMPLE      | users | NULL       | ref  | idx_user_name | idx_user_name | 82      | const |    1 |   100.00 | Using index |

SQL 1和SQL 2的執行計劃中的Extra=Using index 表示使用覆蓋索引掃描,不需要回表,再來看上面的業務SQL:

select user_id, user_name, phone from users where user_name = 'Laaa';

可以看到select後面的user_id,phone列不在索引idx_user_name中,就需要通過主鍵id進行回表查找,MySQL內部分如下兩個階段處理:

Section 1:select **id** from users where user_name = 'Laaa'  //id = 100101

Section 2:   select user_id, user_name, phone from users where id = 100101;

Section 2的操作稱為回表,即通過輔助索引中的主鍵id去原表中查找數據。

索引高度

MySQL的索引時B+tree結構,即使表裡有上億條數據,索引的高度都不會很高,通常維持在3-4層左右,我來計算下索引idx_name的高度,從上面知道索引信息:index_id = 4003, page_no = 5,它的偏移量offset就是page_no x innodo_page_size  + 64 = 81984,通過hexdump進行查看

$hexdump -s 81984 -n 10 /usr/local/var/mysql/test/users.ibd
0014040 00 02 00 00 00 00 00 00 0f a3                  
001404a

其中索引的PAGE_LEVEL為00,即idx_user_name索引高度為1,0f a3 代表索引編號,轉換為十進位是4003,正是index_id。

數據掃描方式

全表掃描

從左到右依次掃描整個B+Tree獲取數據,掃描整個表數據,IO開銷大,速度慢,鎖等嚴重,影響MySQL的並發。

對於OLAP的業務場景,需要掃描返回大量數據,這時候全表掃描的順序IO效率更高。

索引掃描

通常來講索引比表小,掃描的數據量小,消耗的IO少,執行速度塊,幾乎沒有鎖等,能夠提高MySQL的並發。

對於OLTP系統,希望所有的SQL都能命中合適的索引總是美好的。

主要區別就是掃描數據量大小以及IO的操作,全表掃描是順序IO,索引掃描是隨機IO,MySQL對此做了優化,增加了change buffer特性來提高IO性能。

索引優化案例

分頁查詢優化

業務要根據時間範圍查詢交易記錄,接口原始的SQL如下:

select  * from trade_info where status = 0 and create_time >= '2020-10-01 00:00:00' and create_time <= '2020-10-07 23:59:59' order by id desc limit 102120, 20;

表trade_info上有索引idx_status_create_time(status,create_time),通過上面分析知道,等價於索引**(status,create_time,id)**,對於典型的分頁limit m, n來說,越往後翻頁越慢,也就是m越大會越慢,因為要定位m位置需要掃描的數據越來越多,導致IO開銷比較大,這裡可以利用輔助索引的覆蓋掃描來進行優化,先獲取id,這一步就是索引覆蓋掃描,不需要回表,然後通過id跟原表trade_info進行關聯,改寫後的SQL如下:

select * from trade_info a ,

(select  id from trade_info where status = 0 and create_time >= '2020-10-01 00:00:00' and create_time <= '2020-10-07 23:59:59' order by id desc limit 102120, 20) as b   //這一步走的是索引覆蓋掃描,不需要回表
 where a.id = b.id;

很多同學只知道這樣寫效率高,但是未必知道為什麼要這樣改寫,理解索引特性對編寫高質量的SQL尤為重要。

分而治之總是不錯的

營銷系統有一批過期的優惠卷要失效,核心SQL如下:

-- 需要更新的數據量500w
update coupons set status = 1 where status =0 and create_time >= '2020-10-01 00:00:00' and create_time <= '2020-10-07 23:59:59';

在Oracle裡更新500w數據是很快,因為可以利用多個cpu core去執行,但是MySQL就需要注意了,一個SQL只能使用一個cpu core去處理,如果SQL很複雜或執行很慢,就會阻塞後面的SQL請求,造成活動連接數暴增,MySQL CPU 100%,相應的接口Timeout,同時對於主從複製架構,而且做了業務讀寫分離,更新500w數據需要5分鐘,Master上執行了5分鐘,binlog傳到了slave也需要執行5分鐘,那就是Slave延遲5分鐘,在這期間會造成業務髒數據,比如重複下單等。

優化思路:先獲取where條件中的最小id和最大id,然後分批次去更新,每個批次1000條,這樣既能快速完成更新,又能保證主從複製不會出現延遲。

優化如下:

先獲取要更新的數據範圍內的最小id和最大id(表沒有物理delete,所以id是連續的)
mysql> explain select min(id) min_id, max(id) max_id from coupons where status =0 and create_time >= '2020-10-01 00:00:00' and create_time <= '2020-10-07 23:59:59'; 
+----+---+--+--+--+----+----+----+---
| id | select_type | table | partitions | type  | possible_keys          | key                    | key_len | ref  | rows   | filtered | Extra                    |
+----+---+--+--+--+----+----+----+---
|  1 | SIMPLE      | users | NULL       | range | idx_status_create_time | idx_status_create_time | 6       | NULL | 180300 |   100.00 | Using where; Using index |

Extra=Using where; Using index使用了索引idx_status_create_time,同時需要的數據都在索引中能找到,所以不需要回表查詢數據。

以每次1000條commit一次進行循環update,主要代碼如下:
current_id = min_id;
for  current_id < max_id do
  update coupons set status = 1 where id >=current_id and id <= current_id + 1000;  //通過主鍵id更新1000條很快
commit;
current_id += 1000;
done

這兩個案例告訴我們,要充分利用輔助索引包含主鍵id的特性,先通過索引獲取主鍵id走覆蓋索引掃描,不需要回表,然後再通過id去關聯操作是高效的,同時根據MySQL的特性使用分而治之的思想既能高效完成操作,又能避免主從複製延遲產生的業務數據混亂。

MySQL索引設計

熟悉了索引的特性之後,就可以在業務開發過程中設計高質量的索引,降低接口的響應時間。

前綴索引

對於使用REDUNDANT或者COMPACT格式的InnoDB表,索引鍵前綴長度限制為767位元組。如果TEXT或VARCHAR列的列前綴索引超過191個字符,則可能會達到此限制,假定為utf8mb4字符集,每個字符最多4個字節。

可以通過設置參數innodb_large_prefix來開啟或禁用索引前綴長度的限制,即是設置為OFF,索引雖然可以創建成功,也會有一個警告,主要是因為index size會很大,效率大量的IO的操作,即使MySQL優化器命中了該索引,效率也不會很高。

-- 設置innodb_large_prefix=OFF禁用索引前綴限制,雖然可以創建成功,但是有警告。
mysql> create index idx_nickname on users(nickname);    // `nickname` varchar(255)
Records: 0  Duplicates: 0  Warnings: 1
mysql> show warnings;
+----+-+--+
| Level   | Code | Message                                                 |
+----+-+--+
| Warning | 1071 | Specified key was too long; max key length is 767 bytes |

業務發展初期,為了快速實現功能,對一些數據表欄位的長度定義都比較寬鬆,比如用戶表users的暱稱nickname定義為varchar(128),而且有業務接口需要通過nickname查詢,系統運行了一段時間之後,查詢users表最大的nickname長度為30,這個時候就可以創建前綴索引來減小索引的長度提升性能。

-- `nickname` varchar(128) DEFAULT NULL定義的執行計劃
mysql> explain select * from users where nickname = 'Laaa';
+----+---+--+--+-++----+----+--+-+---
| id | select_type | table | partitions | type | possible_keys | key          | key_len | ref   | rows | filtered | Extra |
+----+---+--+--+-++----+----+--+-+---
|  1 | SIMPLE      | users | NULL       | ref  | idx_nickname  | idx_nickname | 515     | const |    1 |   100.00 | NULL  |

key_len=515,由於表和列都是utf8mb4字符集,每個字符佔4個字節,變長數據類型+2Bytes,允許NULL額外+1Bytes,即128 x 4 + 2 + 1 = 515Bytes。創建前綴索引,前綴長度也可以不是當前表的數據列最大值,應該是區分度最高的那部分長度,一般能達到90%以上即可,例如email欄位存儲都是類似這樣的值xxxx@yyy.com,前綴索引的最大長度可以是xxxx這部分的最大長度即可。

-- 創建前綴索引,前綴長度為30
mysql> create index idx_nickname_part on users(nickname(30));
-- 查看執行計劃
mysql> explain select * from users where nickname = 'Laaa';
+----+---+--+--+-+--+----+----+-
| id | select_type | table | partitions | type | possible_keys                  | key               | key_len | ref   | rows | filtered | Extra       |
+----+---+--+--+-+--+----+----+-
|  1 | SIMPLE      | users | NULL       | ref  | idx_nickname_part,idx_nickname | idx_nickname_part | 123     | const |    1 |   100.00 | Using where |

可以看到優化器選擇了前綴索引,索引長度為123,即30 x 4 + 2 + 1 = 123 Bytes,大小不到原來的四分之。

前綴索引雖然可以減小索引的大小,但是不能消除排序。

mysql> explain select gender,count(*) from users where nickname like 'User100%' group by nickname limit 10;
+----+---+--+--+--+--+----+----+
| id | select_type | table | partitions | type  | possible_keys                  | key          | key_len | ref  | rows | filtered | Extra                 |
+----+---+--+--+--+--+----+----+
|  1 | SIMPLE      | users | NULL       | range | idx_nickname_part,idx_nickname | idx_nickname | 515     | NULL |  899 |   100.00 | Using index condition |
--可以看到Extra= Using index condition表示使用了索引,但是需要回表查詢數據,沒有發生排序操作。
mysql> explain select gender,count(*) from users where nickname like  'User100%' group by nickname limit 10;
+----+---+--+--+--+----+----+----+-+-
| id | select_type | table | partitions | type  | possible_keys     | key               | key_len | ref  | rows | filtered | Extra                        |
+----+---+--+--+--+----+----+----+-+-
|  1 | SIMPLE      | users | NULL       | range | idx_nickname_part | idx_nickname_part | 123     | NULL |  899 |   100.00 | Using where; Using temporary |
--可以看到Extra= Using where; Using temporaryn表示在使用了索引的情況下,需要回表去查詢所需的數據,同時發生了排序操作。

複合索引

在單列索引不能很好的過濾數據的時候,可以結合where條件中其他欄位來創建複合索引,更好的去過濾數據,減少IO的掃描次數,舉個例子:業務需要按照時間段來查詢交易記錄,有如下的SQL:

select  * from trade_info where status = 1 and create_time >= '2020-10-01 00:00:00' and create_time <= '2020-10-07 23:59:59';

開發同學根據以往複合索引的設計的經驗:唯一值多選擇性好的列作為複合索引的前導列,所以創建複合索idx_create_time_status是高效的,因為create_time是一秒一個值,唯一值很多,選擇性很好,而status只有離散的6個值,所以認為這樣創建是沒問題的,但是這個經驗只適合於等值條件過濾,不適合有範圍條件過濾的情況,例如idx_user_id_status(user_id,status)這個是沒問題的,但是對於包含有create_time範圍的複合索引來說,就不適應了,我們來看下這兩種不同索引順序的差異,即idx_status_create_time和idx_create_time_status。

-- 分別創建兩種不同的複合索引
mysql> create index idx_status_create_time on trade_info(status, create_time);
mysql> create index idx_create_time_status on trade_info(create_time,status);
-- 查看SQL的執行計劃
mysql> explain select * from users where status = 1 and create_time >='2021-10-01 00:00:00' and create_time <= '2021-10-07 23:59:59';
+----+---+--+--+--+--+
| id | select_type | table | partitions | type  | possible_keys                                 | key                    | key_len | ref  | rows  | filtered | Extra                 |
+----+---+--+--+--+--+
|  1 | SIMPLE      | trade_info | NULL       | range | idx_status_create_time,idx_create_time_status | idx_status_create_time | 6       | NULL | 98518 |   100.00 | Using index condition |

從執行計劃可以看到,兩種不同順序的複合索引都存在的情況,MySQL優化器選擇的是idx_status_create_time索引,那為什麼不選擇idx_create_time_status,我們通過optimizer_trace來跟蹤優化器的選擇。

-- 開啟optimizer_trace跟蹤
mysql> set session optimizer_trace="enabled=on",end_markers_in_json=on;
-- 執行SQL語句
mysql> select * from trade_info where status = 1 and create_time >='2021-10-01 00:00:00' and create_time <= '2021-10-07 23:59:59';
-- 查看跟蹤結果
mysql>SELECT trace FROM information_schema.OPTIMIZER_TRACE\G;

對比下兩個索引的統計數據,如下所示:

複合索引TypeRows參與過濾索引列ChosenCauseidx_status_create_timeIndex Range Scan98518status AND create_timeTrueCost低idx_create_time_statusIndex Range Scan98518create_timeFalseCost高

MySQL優化器是基於Cost的,COST主要包括IO_COST和CPU_COST,MySQL的CBO(Cost-Based Optimizer基於成本的優化器)總是選擇Cost最小的作為最終的執行計劃去執行,從上面的分析,CBO選擇的是複合索引idx_status_create_time,因為該索引中的status和create_time都能參與了數據過濾,成本較低;而idx_create_time_status只有create_time參數數據過濾,status被忽略了,其實CBO將其簡化為單列索引idx_create_time,選擇性沒有複合索引idx_status_create_time好。

複合索引設計原則

將範圍查詢的列放在複合索引的最後面,例如idx_status_create_time。列過濾的頻繁越高,選擇性越好,應該作為複合索引的前導列,適用於等值查找,例如idx_user_id_status。

這兩個原則不是矛盾的,而是相輔相成的。

跳躍索引

一般情況下,如果表users有複合索引idx_status_create_time,我們都知道,單獨用create_time去查詢,MySQL優化器是不走索引,所以還需要再創建一個單列索引idx_create_time。用過Oracle的同學都知道,是可以走索引跳躍掃描(Index Skip Scan),在MySQL 8.0也實現Oracle類似的索引跳躍掃描,在優化器選項也可以看到skip_scan=on。

| optimizer_switch             |use_invisible_indexes=off,skip_scan=on,hash_join=on |

適合複合索引前導列唯一值少,後導列唯一值多的情況,如果前導列唯一值變多了,則MySQL CBO不會選擇索引跳躍掃描,取決於索引列的數據分表情況。

mysql> explain select id, user_id,status, phone from users where create_time >='2021-01-02 23:01:00' and create_time <= '2021-01-03 23:01:00';
+----+---+--+--+-++-+----+-+---++----
| id | select_type | table | partitions | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra       |
+----+---+--+--+-++-+----+-+---++----
|  1 | SIMPLE      | users | NULL       | range  | idx_status_create_time          | idx_status_create_time | NULL    | NULL | 15636 |    11.11 | Using where; Using index for skip scan|

也可以通過optimizer_switch='skip_scan=off'來關閉索引跳躍掃描特性。

總結

本位為大家介紹了MySQL中的索引,包括聚集索引和輔助索引,輔助索引包含了主鍵id用於回表操作,同時利用覆蓋索引掃描可以更好的優化SQL。

同時也介紹了如何更好做MySQL索引設計,包括前綴索引,複合索引的順序問題以及MySQL 8.0推出的索引跳躍掃描,我們都知道,索引可以加快數據的檢索,減少IO開銷,會佔用磁碟空間,是一種用空間換時間的優化手段,同時更新操作會導致索引頻繁的合併分裂,影響索引性能,在實際的業務開發中,如何根據業務場景去設計合適的索引是非常重要的,今天就聊這麼多,希望對大家有所幫助。

我是敖丙,你知道的越多,你不知道的越多,感謝各位的三連,我們下期見。

相關焦點

  • Mysql如何給字符串添加索引(前綴索引)
    在日常開發中,我們經常給字符串添加索引,那麼給欄位添加索引有什麼技巧嗎,我們看看下面的例子,我們給一個郵箱添加索引,應該如何添加呢看看下面這條
  • MySQL索引與索引優化
    索引是對資料庫表中一個或多個列的值進行排序的結構,建立索引有助於快速獲取信息。你也可以這樣理解:索引就是加快檢索表中數據的方法。資料庫的索引類似於書籍的索引。在書籍中,索引允許用戶不必翻閱完整個書就能迅速地找到所需要的信息。在資料庫中,索引也允許資料庫程序迅速地找到表中的數據,而不必掃描整個資料庫。
  • 機器學習時代的哈希算法,將如何更高效地索引數據
    哈希算法一直是索引中最為經典的方法,它們能高效地儲存與檢索數據。但在去年 12 月,Jeff Dean 與 MIT 等研究者將索引視為模型,探索了深度學習模型學習的索引優於傳統索引結構的條件。本文首先將介紹什麼是索引以及哈希算法,並描述在機器學習與深度學習時代中,如何將索引視為模型學習比哈希算法更高效的表徵。
  • 以色列專業護膚品牌Christina 攜多款經典系列亮相廣州美博
    這已經是我連續第四次來參加美博會了,我感到非常的親切。我在Christina公司擔任教育部部長一職,主要負責Christina全球教育培訓事務。中國是我經常來的一個國家,每年我在中國都有數場Christina中國區官方運營商安悅國際組織的展會、研討會、講座、沙龍等。中國人民非常的熱情友好,我非常喜歡中國。
  • Redis面試:八問字典內部構造與rehash,給我整懵了
    哈希如何實現字典之前寫過一篇文章,關於java中的hashcode解析,有興趣的讀者可以回看下一些經典的hash函數和實現面試官問我:hashcode 是什麼?和equals是兄弟嗎?字典如何增添一個元素當要將一個新的鍵值對加入到字典中的時候,首先要計算這個key的哈希值和索引值,然後再根據這個索引值放入字典中h[0]的索引位置舉個例子, 對於圖 4-4 所示的字典來說, 如果我們要將一個鍵值對 k0 和 v0 添加到字典裡面, 那麼程序會先使用語句:hash
  • 從原理到優化,深入淺出資料庫索引 - 計算機java編程
    >DROPINDEX index_name ON table_name;三、索引樹是如何維護的目前大部分資料庫系統及文件系統都採用B-Tree或其變種B+Tree作為索引結構,那麼索引樹是如何維護的?如果你用範圍約束或如果執行索引掃描來查詢索引列,該值增加。Handler_read_prev:按照鍵順序讀前一行的請求數。該讀方法主要用於優化ORDER BY ... DESC。Handler_read_rnd :根據固定位置讀一行的請求數。如果你正執行大量查詢並需要對結果進行排序該值較高。
  • 教你製作樂高零件牆索引標籤紙
    國外網友的零件牆那麼新的問題來了,在零件牆搭建完成之後,如何建立索引以便自己可以快速的定位並找到需要的零件呢?今天就為大家分享一種自己列印零件盒索引標籤的方法。最終的效果就像下方點哥自己列印的這種零件索引標籤。
  • 資料庫面試常見問題:前綴索引、索引下推-開課吧
    資料庫面試1、前綴索引因為可能我們索引的欄位常,這既佔內存空間,也不利於維護。所以我們就想,如果只把很欄位的前的公共部分作為個索引,就會產超級加倍的效果。索引下推 (阿社招 )MySQL 5.6引了索引下推優化。默認開啟,使 SET optimizer_switch = 『index_condition_pushdown=offff』; 可以將其關閉。
  • 2020火熱的一個索引!快來了解一下吧!
    平時的時候人們快速準確的查詢信息庫中的信息,經常會給表中的欄位添加索引,因為這樣是最快的一種方法了,那麼大家考慮過如何添加索引才能使索引變得更高效嗎,如果說加了索引,索引本身是有序的,所以從磁碟讀的行數本身就是按 age 排序好的。
  • 網站首頁引流,索引丟失,什麼原因,怎麼恢復?
    如果你是一個企業網站的運營者,我們每天幾乎都會遇到各種問題,特別是對於SEO方面相關的事情,其中企業網站首頁莫名其妙的丟索引,可能是最讓SEO人員頭疼的一件事情。
  • 媒體檢索排序與哈希索引簡介
    其方法是先通過使用不同的深層神經網絡模型對不同類型媒體數據建模(如對圖像使用深度卷積網絡和對文本使用深度結構語義模型),然後在深層模型頂層設計基於交叉熵的損失層,通過逐層反饋排序損失來進行深度模型的訓練和優化。
  • Mysql為啥用B+樹來做索引?
    一、為什麼需要索引?大家都知道,我們讀取數據時要避免全表掃描,那如何避免全表掃描呢?目前科學家給出的目標就是索引。索引就好比一本字典的目錄一樣,有了目錄讀者就不需要翻找全書來找內容。同樣有了索引,資料庫就不用全表掃描了。在一張數據表中不管你建不建索引都會有一個默認索引。
  • 字節跳動三面offer到手,面試官都問了些啥?
    原標題:字節跳動三面offer到手,面試官都問了些啥?     前段時間,我一哥們去面試字節跳動,我聽他說過程艱難,但還是費了九牛二虎之力拿下了。     字節跳動的面試挺有挑戰性的感覺,不過還是挺有趣的,感覺啥技術都問。今天就跟大家說說字節跳動的面經。
  • MySQL 8.0 中的索引可以隱藏了…
    MySQL 8.0 雖然發布很久了,但可能大家都停留在 5.7.x,甚至更老,其實 MySQL 8.0 新增了許多重磅新特性,比如棧長今天要介紹的 "隱藏索引" 或者 "不可見索引"。隱藏索引是什麼鬼?
  • YellowDog的突破性索引削減了雲計算的成本
    YellowDog索引消除了複雜性,提供了有關成本,性能,可用性和碳影響方面的全球所有實例的清晰,有序的視圖。雲客戶有史以來第一次能夠立即找到與他們的需求完全匹配的最佳計算源。該索引使用可從綠色和平組織和美國能源信息管理局等來源獲得的最新信息。
  • PyTorch官方教程大更新:增加標籤索引,更加新手友好
    PyTorch官方教程大更新:增加標籤索引,更加新手友好 2020-05-17 19:08 來源:澎湃新聞·澎湃號·湃客
  • ElasticSearch 中的中文分詞器以及索引基本操作詳解
    2.1 新建索引2.1.1 通過 head 插件新建索引在 head 插件中,選擇 索引選項卡,然後點擊新建索引。新建索引時,需要填入索引名稱、分片數以及副本數。索引名是唯一的,不能重複,重複創建會出錯2.2 更新索引索引創建好之後,可以修改其屬性。
  • 漲知識了|期刊索引的SCI、SSCI、EI、ISTP、ISSHP…是什麼意思?
    期刊索引的SCI、SSCI、EI、ISTP、ISSHP……都是什麼意思?目前,在國際科學界與學術界,如何正確評價基礎科學研究成果已引起越來越廣泛的關注。而被ISI旗下的SCI、SSCI、EI和ISTP等重要檢索期刊所收錄科技論文的多寡則被看作衡量一個國家、一個單位的基礎科學研究水平、科技實力和科技論文水平高低的重要評價指標。
  • 為什麼 MongoDB 索引選擇B-樹,而 Mysql 選擇B+樹(精幹總結)
    這個問題是我在看視頻的時候老師提到的,雖然之前知道他們各自的索引結構但是還沒有研究過原因。在網上一搜答案特別多。但是都特別的囉嗦。於是總結了這篇文章。針對我們這個問題的最核心的特點如下:(1)多路,非二叉樹(2)每個節點既保存索引,又保存數據(3)搜索時相當於二分查找在這裡我們假定都已經了解了B樹相關的結構。
  • 不要問我心裡有沒有你,我余光中都是你
    最近喜歡上了一句話,一個詩人,他曾對妻子在信中說到,不要問我心裡有沒有你,我余光中都是你,是不是很動人?這個詩人就是余光中,牙痛可以拔掉,胃痛可以吃藥,你在我心裡,要我把心挖出來扔掉嗎?