mysql 模拟条件索引
我们知道,mysql 不支持条件索引。 什么是条件索引呢? 条件索引就是在索引列上根据where条件进行一定的过滤后产生的索引。 这样的索引有以下优势:
第一点, 比基于这个列的全部索引占用空间来的小。
第二点, 特别是基于full index scan 的时候,占用空间小的索引对内存占用也小很多。
postgresql,sqlserver等都支持条件索引,所以我们先来看下条件索引的实际情况。
表结构如下,记录大概有10w行:
table "ytt.girl1"
column | type | modifiers
--------+---------+--------------------
id | integer | not null
rank | integer | not null default 0
indexes:
"girl1_pkey" primary key, btree (id)
"idx_girl1_rank" btree (rank) where rank >= 10 and rank <= 100
执行的查询语句为:
select * from girl1 where rank between 20 and 60 limit 20;
用了全部索引的查询计划:
query plan
---------------------------------------------------------------------------------------------------------------------------------
limit (cost=0.29..36.58 rows=20 width=8) (actual time=0.024..0.054 rows=20 loops=1)
-> index scan using idx_girl1_rank on girl1 (cost=0.29..421.26 rows=232 width=8) (actual time=0.023..0.044 rows=20 loops=1)
index cond: ((rank >= 20) and (rank <= 60))
total runtime: 0.087 ms
(4 rows)
time: 1.881 ms
用了条件索引的查询计划:
query plan
---------------------------------------------------------------------------------------------------------------------------------
limit (cost=0.28..35.54 rows=20 width=8) (actual time=0.036..0.068 rows=20 loops=1)
-> index scan using idx_girl1_rank on girl1 (cost=0.28..513.44 rows=291 width=8) (actual time=0.033..0.061 rows=20 loops=1)
index cond: ((rank >= 20) and (rank <= 60))
total runtime: 0.106 ms
(4 rows)
time: 0.846 ms可以看出,在扫描的记录数以及时间上,条件索引的优势都很明显。
接下来,我们在mysql 模拟下这样的过程。
由于mysql 不支持这样的索引, 在sql层面上,只能创建一个索引表来保存对应条件的主键以及索引键。
ytt>show create table girl1_filtered_index;
+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| table | create table |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| girl1_filtered_index | create table `girl1_filtered_index` (
`id` int(11) not null,
`rank` int(11) not null default '0',
primary key (`id`),
key `idx_rank` (`rank`)
) engine=innodb default charset=latin1 |
+----------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
接下来,对基础表的更新操作做下修改,创建了三个触发器。
delimiter $$
use `t_girl`$$
drop trigger /*!50032 if exists */ `filtered_insert`$$
create
/*!50017 definer = 'root'@'localhost' */
trigger `filtered_insert` after insert on `girl1`
for each row begin
if new.rank between 10 and 100 then
insert into girl1_filtered_index values (new.id,new.rank);
end if;
end;
$$
delimiter ;
delimiter $$
use `t_girl`$$
drop trigger /*!50032 if exists */ `filtered_update`$$
create
/*!50017 definer = 'root'@'localhost' */
trigger `filtered_update` after update on `girl1`
for each row begin
if new.rank between 10 and 100 then
replace girl1_filtered_index values (new.id,new.rank);
else
delete from girl1_filtered_index where id = old.id;
end if;
end;
$$
delimiter ;
delimiter $$
use `t_girl`$$
drop trigger /*!50032 if exists */ `filtered_delete`$$
create
/*!50017 definer = 'root'@'localhost' */
trigger `filtered_delete` after delete on `girl1`
for each row begin
delete from girl1_filtered_index where id = old.id;
end;
$$
delimiter ;
ok,我们导入测试数据。
ytt>load data infile 'girl1.txt' into table girl1 fields terminated by ',';
query ok, 100000 rows affected (1.05 sec)
records: 100000 deleted: 0 skipped: 0 warnings: 0
ytt>select count(*) from girl1;
+----------+
| count(*) |
+----------+
| 100000 |
+----------+
1 row in set (0.04 sec)
ytt>select count(*) from girl1_filtered_index;
+----------+
| count(*) |
+----------+
| 640 |
+----------+
1 row in set (0.00 sec)这里,我们把查询语句修改成基础表和条件索引表的join。
select a.id,a.rank from girl1 as a where a.id in (select b.id from girl1_filtered_index as b where b.rank between 20 and 60) limit 20;
当然这只是功能上的一个演示。 最终实现得靠mysql 5.8了。^____^
【说明】:本文章由站长整理发布,文章内容不代表本站观点,如文中有侵权行为,请与本站客服联系(QQ:254677821)!