mysql 前缀索引

大家都知道在CHAR和VARCHAR列上,可以使用列的前缀进行索引,如:INDEX (name(10),address(20))

但是到底第几位是optimal length 呢?

http://www.shinguz.ch/MySQL/mysql_hints.html的一部分介绍如下:
For CHAR, VARCHAR, BINARY, and VARBINARY columns, indexes (called prefixed indexes) can be created that use only part of a column, using col_name(length) syntax to specify an index prefix length.
These indexes are shorter and thus safe space (on disk and in memory) and can be faster than non prefixed indexes.
But shortening indexes can reduce cardinality(=(select count (DISTINCT my_column ) FROM my_table)计算方法) of an index and is thus worse.
With this statement you can find out the optimal length of an prefixed index. Optimal means close than or equal cardinality to the full index.
SELECT COUNT(DISTINCT LEFT(my_column, <n>)) card FROM my_table;
Let's assume that we have an index on my_column VARCHAR(32) with a cardinality of 1142 we can say after some trials (increasing n from 1 to ...), that a prefixed index with more than 6 characters length does NOT make sense with the present da ta (except when we retrieve the da ta from the index on ly (index look up)).
例如:
+---+-------+
| n | card  |
+---+-------+
| 4 |  258  |
| 5 |  741  |
| 6 | 1142  |
+---+-------+

(索引占用空间数的计算:
Let's assume, that we have approx. 1 Mio rows in this table with an utf8 character set (3 bytes per character) then the original index has a size of 97 Mio bytes (1 Mio x (1 + 3 x 32)). But our prefixed index has a size of on ly 19 Mio bytes (1 Mio x ( 1 + 3 x 6)). This is a gain of approx 80% of space (and also some performance)!)

通过上面的介绍,写一存储来求optimal length

/* 简单判断 前缀索引取的是列的前几位 使用方法:call prefixindex('表名','列名');select @leng; */
DELIMITER $$

DROP PROCEDURE IF EXISTS `prefixindex`$$

CREATE DEFINER=`root`@`localhost` PROCEDURE `prefixindex`(IN name1 varchar(20),IN name2 varchar(20))
BEGIN
DECLARE i int default 1;
select name1 into @tablesname;
select name2 into @columnname;
set @stmt=CONCAT('select  count(DISTINCT ',@columnname,') into @cardinality from ',  @tablesname);
prepare s1 from @stmt;
execute s1;
deallocate prepare s1;
label_1: while i>0
do
set @leng=i;
set @stmt=CONCAT('select count(DISTINCT LEFT(',@columnname,',',@leng,')) into @cardinality1 from ',  @tablesname);
prepare s2 from @stmt;
execute s2;
deallocate prepare s2;
if @leng=1 then
select abs(@cardinality1-@cardinality) into @diffvalue1;
else select abs(@cardinality1-@cardinality) into @diffvalue2;
if @diffvalue1>@diffvalue2 or @diffvalue1>3 /*自己确定的精度,可以让更接近cardinality*/
then set @diffvalue1=@diffvalue2;
else
leave label_1;
end if;
end if;
set i=i+1;
end while;
set @stmt='';
END$$
DELIMITER ;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值