日期:2014-05-16  浏览次数:20549 次

MariaDB 实现函数索引
我们知道MySQL 暂时不支持函数索引。 目前大部分数据库包括PostgreSQL,Oracle等都支持。 什么是函数索引呢?
函数索引就是说用某固定的函数来对列生成一个基于此函数结果集的索引树。 好处是开发人员写SQL变得随意而且简单了,但是不好的一点也是如此,必须写按照固定条件进行的读取过滤。


在之前呢,如果要实现这样的功能,MySQL 得创建一个新的列,然后用前置触发器来修改此列的值。  现在呢,MariaDB有一个虚拟列的特性可以很方便的来实现这个目的。
先来看下在PostgreSQL中的表结构
t_girl=# \d email_list;
             Table "public.email_list"
  Column  |            Type             | Modifiers 
----------+-----------------------------+-----------
 id       | integer                     | 
 email    | character varying(200)      | 
 log_time | timestamp without time zone | 
Indexes:
    "idx_email_suffix" btree (substr(email::text, "position"(email::text, '@'::text) + 1))




  这张表的EMAIL列属性上有一个函数索引,目的是来查找次EMAIL属性是属于哪家提供商,比如163,GMAIL等等。


我们给张表产生了20W行记录。
t_girl=# select count(*) from email_list;
 count  
--------
 200000
(1 row)


Time: 39.851 ms




现在来进行对应的查询。 如果不严格按照这个函数的创建规范,查询就不走索引,所以一定要严格来写SQL。
                                                              QUERY PLAN                                                              
--------------------------------------------------------------------------------------------------------------------------------------
 Aggregate  (cost=1607.19..1607.20 rows=1 width=12) (actual time=5.514..5.514 rows=1 loops=1)
   ->  Bitmap Heap Scan on email_list  (cost=48.29..1602.08 rows=2047 width=12) (actual time=1.126..4.806 rows=1960 loops=1)
         Recheck Cond: (substr((email)::text, ("position"((email)::text, '@'::text) + 1)) = '56.com'::text)
         ->  Bitmap Index Scan on idx_email_suffix  (cost=0.00..47.78 rows=2047 width=0) (actual time=0.802..0.802 rows=1960 loops=1)
               Index Cond: (substr((email)::text, ("position"((email)::text, '@'::text) + 1)) = '56.com'::text)
 Total runtime: 5.603 ms
(6 rows)


Time: 6.601 ms




从查询分析计划中看到,走这个函数索引,扫描了大概2K行记录,生成结果集1960行。


t_girl=# select count(email) as num from email_list where substr(email,position('@' in email)+1)='56.com';
 num  
------
 1960
(1 row)


Time: 5.251 ms
t_girl=# 




接下来,我们看看在MariaDB中如何来实现对应的功能。
表结构如下:
MariaDB [t_girl]> show create table email_list;
+------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table      | Create Table                                                                                                                                                                                                                                                                                                |
+------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| email_list | CREATE TABLE `email_list` (
  `id` int(11) DEFAULT NULL,
  `email` varchar(200) DEFAULT NULL,
  `log_time` datetime(6) DEFAULT NULL,
  `email_suffix` varchar(100) AS (substr(email,position('@'