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 ;

你可能感兴趣的:(mysql,table,存储,character,performance,disk)