MySQL 模拟条件索引

7 篇文章 0 订阅
4 篇文章 0 订阅
我们知道,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了。^____^
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
MySQL中,我们可以使用ORDER BY子句来对查询结果进行排序。然而,当数据库中包含大量数据时,对查询进行排序可能会导致查询性能下降。为了解决这个问题,我们可以在查询中添加一个ORDER BY索引来加速排序操作。 ORDER BY索引是一个特殊类型的索引,它与排序顺序有关。它不仅包含要排序的列的值,还包含用于排序的列的排序顺序。 创建ORDER BY索引时需要注意一些事项: 1. 使用正确的排序顺序:如果查询中使用的是ASC排序,则ORDER BY索引也必须使用ASC排序;如果查询中使用的是DESC排序,则ORDER BY索引也必须使用DESC排序。 2. 考虑添加其他列:如果查询中还包含其他列,可以考虑添加这些列到ORDER BY索引中,以减少后续对表的访问次数。 3. 了解索引的限制:ORDER BY索引只适用于特定的查询场景,例如只对一个或多个列进行排序的查询。如果有其他条件或涉及多个表的连接查询,则ORDER BY索引可能不起作用。 创建ORDER BY索引的语法如下: CREATE INDEX index_name ON table_name (column1 [ASC|DESC], column2 [ASC|DESC], ...); 在使用ORDER BY索引时,我们可以看到查询的执行速度明显加快。这是因为ORDER BY索引允许数据库直接按照索引中的排序顺序返回结果,而无需对查询结果进行排序。但是,有时候创建ORDER BY索引可能会导致插入、更新或删除数据的性能下降,因此需要根据具体情况进行权衡和测试。 总之,使用ORDER BY索引可以提高查询性能,特别是在处理大量数据时。但是在使用前需要了解其限制,并根据具体情况进行权衡和测试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值