教学之友,学习之友。

站长教学网

当前位置: 站长教学网 > 数据库 > MYSQL教程 >

mysql前缀索引

时间:2013-04-12 15:08来源:未知 作者:ken 点击:

大家都知道在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 data (except when we retrieve the data from the index only (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 only 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 ;

 

(责任编辑:ken)
TAG标签: mysql 前缀索引
顶一下
(0)
0%
踩一下
(0)
0%
------分隔线----------------------------
发表评论
请自觉遵守互联网相关的政策法规,严禁发布色情、暴力、反动的言论。
评价:
表情:
注册登录:不允许匿名留言,登录后留言无需输入验证码。
栏目列表
最新内容