use*_*564 8 mysql innodb primary-key clustered-index
假设我有一个 1 对 N 的关系(person_id, pet_id)。我有一张表,pet_id主键在哪里。
我知道 InnoDB 二级索引本质上是一个 B 树,其中值是行的相应主键值。
现在,假设一个人可以拥有数千只宠物,而我通常希望一个人的宠物按pet_id. 那么,如果在第二个索引记录的排序会的问题(person_id, pet_id)或只是person_id用pet_id的该person_id是无序。猜到后来。
那么,如果person_id是非唯一的,记录是按物理排序(person_id, pet_id)还是仅排序pet_id?
谢谢
否。如果您的表具有 InnoDB 引擎并且PRIMARY KEYis (pet_id),则将二级索引定义为(person_id)或(person_id, pet_id)没有区别。
索引也包括该pet_id列,因此(person_id, pet_id)在两种情况下都对值进行排序。
像您这样的查询:
SELECT pet_id FROM yourtable
WHERE person_id = 127
ORDER BY pet_id ;
Run Code Online (Sandbox Code Playgroud)
将只需要访问索引来获取值,甚至更多,它不需要进行任何排序,因为pet_id值已经在索引中排序。您可以通过查看执行计划 ( EXPLAIN)来验证这一点:
首先,我们尝试使用 MyISAM 表:
CREATE TABLE table pets
( pet_id int not null auto_increment PRIMARY KEY,
person_id int not null,
INDEX person_ix (person_id)
) ENGINE = myisam ;
INSERT INTO pets (person_id)
VALUES (1),(2),(3),(1),(2),(3),(4),(1),(8),(1),(2),(3) ;
mysql> EXPLAIN SELECT pet_id FROM pets
WHERE person_id = 2
ORDER BY pet_id asc \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: pets
type: ref
possible_keys: person_ix
key: person_ix
key_len: 4
ref: const
rows: 3
Extra: Using where; Using filesort
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
注意文件排序!
现在,带有复合索引的 MyISAM:
DROP TABLE IF EXISTS pets ;
CREATE TABLE table pets
( pet_id int not null auto_increment PRIMARY KEY,
person_id int not null,
INDEX person_ix (person_id, pet_id) -- composite index
) ENGINE = myisam ;
INSERT INTO pets (person_id)
VALUES (1),(2),(3),(1),(2),(3),(4),(1),(8),(1),(2),(3) ;
mysql> EXPLAIN SELECT pet_id FROM pets
WHERE person_id = 2
ORDER BY pet_id asc \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: pets
type: ref
possible_keys: person_ix
key: person_ix
key_len: 4
ref: const
rows: 3
Extra: Using where; Using index
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
Filesort 不见了,正如预期的那样。
现在让我们用 InnoDB 引擎试试同样的方法:
DROP TABLE IF EXISTS pets ;
CREATE TABLE table pets
( pet_id int not null auto_increment PRIMARY KEY,
person_id int not null,
INDEX person_ix (person_id) -- simple index
) ENGINE = innodb ; -- InnoDB engine
INSERT INTO pets (person_id)
VALUES (1),(2),(3),(1),(2),(3),(4),(1),(8),(1),(2),(3) ;
mysql> EXPLAIN SELECT pet_id FROM pets
WHERE person_id = 2
ORDER BY pet_id asc \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: pets
type: ref
possible_keys: person_ix
key: person_ix
key_len: 4
ref: const
rows: 3
Extra: Using where; Using index
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
也没有文件排序!即使索引没有明确包含该pet_id列,值也存在并排序。您可以检查是否使用 定义索引(person_id, pet_id),EXPLAIN是否相同。
让我们用 InnoDB 和复合索引来实际操作:
DROP TABLE IF EXISTS pets ;
CREATE TABLE table pets
( pet_id int not null auto_increment PRIMARY KEY,
person_id int not null,
INDEX person_ix (person_id, pet_id) -- composite index
) ENGINE = innodb ; -- InnoDB engine
INSERT INTO pets (person_id)
VALUES (1),(2),(3),(1),(2),(3),(4),(1),(8),(1),(2),(3) ;
mysql> EXPLAIN SELECT pet_id FROM pets
WHERE person_id = 2
ORDER BY pet_id asc \G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: pets
type: ref
possible_keys: person_ix
key: person_ix
key_len: 4
ref: const
rows: 3
Extra: Using where; Using index
1 row in set (0.00 sec)
Run Code Online (Sandbox Code Playgroud)
与前一个案例相同的计划。
为了 100% 确定,我还运行了最后两个案例(InnoDB 引擎,具有单索引和复合索引)启用file_per_table设置并在表中添加了几千行:
DROP TABLE IF EXISTS ... ;
CREATE TABLE ... ;
mysql> INSERT INTO pets (person_id)
VALUES (1),(2),(3),(1),(2),(3),(4),(1),(8),(1),(2),(3) ;
Query OK, 12 rows affected (0.00 sec)
Records: 12 Duplicates: 0 Warnings: 0
mysql> INSERT INTO pets (person_id)
VALUES (1),(2),(3),(1),(2),(3),(4),(1),(8),(1),(2),(3),(127) ;
Query OK, 13 rows affected (0.00 sec)
Records: 13 Duplicates: 0 Warnings: 0
mysql> INSERT INTO pets (person_id)
VALUES (1),(2),(3),(1),(2),(3),(4),(1),(8),(1),(2),(3),(127) ;
Query OK, 13 rows affected (0.00 sec)
Records: 13 Duplicates: 0 Warnings: 0
mysql> INSERT INTO pets (person_id)
SELECT a.person_id+b.person_id-1
FROM pets a CROSS JOIN pets b CROSS JOIN pets c ;
Query OK, 54872 rows affected (0.47 sec)
Records: 54872 Duplicates: 0 Warnings: 0
Run Code Online (Sandbox Code Playgroud)
在这两种情况下,检查实际文件大小都会产生相同的结果:
ypercube@apollo:~$ sudo ls -la /var/lib/mysql/x/ | grep pets
-rw-rw---- 1 mysql mysql 8604 Apr 21 07:25 pets.frm
-rw-rw---- 1 mysql mysql 11534336 Apr 21 07:25 pets.ibd
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1966 次 |
| 最近记录: |