用自增INT字段做主键应该是效率最高的。现在的情况是这样的:  - C程序在写MySQL数据库时,同时会在内存中缓存一定时间的内记录  - 有个关联引擎会对这些记录进行关联运算,关联运算可能生成新的所谓关联记录  - 关联记录有可能被更新(新进来的记录匹配以前的关联)  - 数据库暂时连不上时希望能先在本地硬盘进行缓存,然后不断重试连接数据库  - 希望关联引擎与写数据库的模块分别由两个独立的线程完成基于以上考虑,希望能由C程序自己生成主键的值。比较靠谱的方法是生成36个字节的UUID(类似c2ece7c0-5ca1-11df-a08a-0800200c9a66),它的唯一性不受进程重启,机器重启等的影响。现在的问题是用这种36字节的UUID做主键,会不会对数据库插入、查找、更新操作造成严重的性能影响?

解决方案 »

  1.   

    按200万条记录,用户数不超过5个,通过Web界面显示,每隔5秒显示最新的大约100条记录
      

  2.   

    200万条记录:字段数有多少,在UUID上建立索引没有
    如果字段数不多,对性能没有多大影响
      

  3.   

    先要判断,是否必要:
    1 数据有没有那么多
    2 数据会不会在不同的Master上生成UUID也分好几类:/**
     * 
     * A class that represents an immutable universally unique identifier (UUID). 
     * A UUID represents a 128-bit value.
     *
     * <p>There exist different variants of these global identifiers. The methods
     * of this class are for manipulating the Leach-Salz variant, although the
     * constructors allow the creation of any variant of UUID (described below).
     * 
     * <p>The layout of a variant 2 (Leach-Salz) UUID is as follows:
     *
     * The most significant long consists of the following unsigned fields:
     * <pre>
     * 0xFFFFFFFF00000000 time_low
     * 0x00000000FFFF0000 time_mid
     * 0x000000000000F000 version
     * 0x0000000000000FFF time_hi
     * </pre>
     * The least significant long consists of the following unsigned fields:
     * <pre>
     * 0xC000000000000000 variant
     * 0x3FFF000000000000 clock_seq
     * 0x0000FFFFFFFFFFFF node
     * </pre>
     *
     * <p>The variant field contains a value which identifies the layout of
     * the <tt>UUID</tt>. The bit layout described above is valid only for
     * a <tt>UUID</tt> with a variant value of 2, which indicates the
     * Leach-Salz variant.
     *
     * <p>The version field holds a value that describes the type of this
     * <tt>UUID</tt>. There are four different basic types of UUIDs: time-based,
     * DCE security, name-based, and randomly generated UUIDs. These types
     * have a version value of 1, 2, 3 and 4, respectively.
     * 
     * <p>For more information including algorithms used to create <tt>UUID</tt>s,
     * see <a href="http://www.ietf.org/rfc/rfc4122.txt">
     * <i>RFC&nbsp;4122: A Universally Unique IDentifier (UUID) URN
     * Namespace</i></a>, section 4.2 &quot;Algorithms for Creating a Time-Based
     * UUID&quot;.
     *
     * @version 1.18, 06/02/06
     * @since   1.5
     */
    摘自jdk的UUID注释其中第4类,也就是完全随机生成的UUID,比如:
    33d2cb38-303a-4886-b4b2-09016ad548f1
    eb6f71cc-9aff-4f29-a674-56c7a8bf5938
    0e6c77c9-425b-4678-baee-36808ad89e96在主键/索引里面的顺序是
    0e6c77c9-425b-4678-baee-36808ad89e96
    33d2cb38-303a-4886-b4b2-09016ad548f1
    eb6f71cc-9aff-4f29-a674-56c7a8bf5938与其物理存储的位置不相符,导致索引之后需要扫描相应行的其他字段的时候,需要往复运动,影响效率。而基于时钟的或者其他相对“顺序”的UUID,就不会有这个问题。因此选用的时候必须考虑清楚。
      

  4.   

    30个字段。在MySQL中主键不是自动建立索引吗?
      

  5.   

    是这样,你不是讲用UUID字段做主键吗?还要考虑UUID生成的方式,如4楼所述
      

  6.   

    多谢几位!OS提供的是DCE类型的UUID。似乎是按单调递增的顺序产生的,但其文本串表示似乎是反着的,例如:a3eea910-5cab-11df-bbb5-000c29e30cf0
    aa75904a-5cab-11df-bbb5-000c29e30cf0
    b1efddae-5cab-11df-bbb5-000c29e30cf0
    bff83279-5cab-11df-bbb5-000c29e30cf0
    c1d87ba7-5cab-11df-bbb5-000c29e30cf0
    0828093c-5cac-11df-bbb5-000c29e30cf0
    30a06204-5cad-11df-bbb5-000c29e30cf0是不是用的时候把顺序倒过来,就可以大大提高性能?比如最后一个改成:
    000c29e30cf0-bbb5-11df-5cad-30a06204
      

  7.   

    你现在的这个格式不是UUID了,如果需要和其他外部接口,就会有点问题,还要来回转。
      

  8.   


    如果这样,应该来说影响不大,你的主键相当于
    uuid char(36) primary key
      

  9.   


    不会,反而不如正着!正着的时候,通过第一个字符,就可以减少很多记录。而反过来,你要到第十几个字符才发现不同。不利于Btree索引。
      

  10.   

    哦,这样的啊,学习了!我还以为建索引时是按字典序排的呢。可你的说法和shine333的有矛盾啊:
    按你的说法,反而是随机生成的UUID效率高,这有点违反直觉
      

  11.   

    实践是检验真理的唯一标准。lz还是实测为好。我的也只是理论。而且,不同的应用,优化方式也不一样。建议lz模拟实际情况,造一点测试数据,量大一点。如果UUID涉及到系统时间,也请模拟一下。刚刚看了狼头的回复。我想到另外一个问题,就是完全按照时间数序录入的二叉树,可能会变成最差二叉树,用一段时间需要重建索引。
      

  12.   

    按你的说法,反而是随机生成的UUID效率高,这有点违反直觉
    很明显你觉得让你在上述两个数据中找出某个值,你觉得哪个快?
      

  13.   

    嗯,看来我的直觉是建立在字典序线性索引基础上的,这时反着插入的效率是最高的,查找时效率应该是比Btree效率低
      

  14.   

    我同意,应该保持UUID()函数返回原样。——这个函数在replication的时候,不能使用statement方式同步。但是,我纠结的是,
    我16777216条测试记录,没有看出明显差异(包括添加其他各种字段,包括text),唯一的区别是,空间上似乎改变顺序后大了很多(无论是数据的,还是在其他字段上加的索引占据的空间)。选择优化表后,空间一致。求解释。我理论上认为开头不一致的btree会层次更少,应该更快。
      

  15.   

    平均访问时间取决于任意两个UUID串(Key值)的比较运算"<",如果平均起来,差不多,就分不出什么差别。
      

  16.   

    可以使用 binary(16) not null来存储uuid(中间的-删除哈) 
    unhex(replace('a3eea910-5cab-11df-bbb5-000c29e30cf0','-','');
    检索出来的时候用hex()这样主键只有原来的一半,效率要高些