Mysql SQL优化(二) 快速生成5位数不重复的编号

要求:生成一个5位数编号 左边不足用0补齐,这个编号不能重复 ,客户可以手动输入编号 ,所有的编号都不能有4这个数字

以前做项目的时候,生成序列号嘛

一是使用UUID

二是利用数据库序列

三是用数据库总条数+1

UUID不和题意,不考虑  MySQL没有序列 需要建表,先放一放

总条数+1 似乎还不错 但是 客户手动输入的编号越多 越容易重复 ,容量也越小

之前的新司机 在java代码用10W次循环 拼接 00000 - 99999 个数字 ,每一次都检查一下数据库有没有重复

public static String doGenerateMemberCode() {
		String memberCode = "";
		for (int i = 0; i < 100000; i++) {
			int sum = i;
			String memberCode2 = "";
			String memberCode3 = "";
			while (true) {
				sum++;
				memberCode2 = "" + sum;
				if (RegularExpressionUtil.checkMemberCodeUnlimited(memberCode2)) {
					break;
				}
			}
			for (int z = memberCode2.length(); z < 5; z++) {
				memberCode3 = "0" + memberCode3;
			}
			memberCode = memberCode3 + memberCode2;
			V_membership v_membership3 = new V_membership();
			v_membership3.setM_code(memberCode);
			if (checkMemberByMember_code(v_membership3)) {
				if (memberCode.length() > 5) {// 如果生成的会员号码大于99999则返回""空字符串
					return "";
				} else {
					return memberCode;
				}
			}
		}
		return memberCode;
	}

说不出话来。。。。。。。。。。

后来数据量大了,卡的用不了,叫我来改

---------------         一段时间后        --------------

解决方案 , 加入一张序列表 两个字段 一个id主键 一个判断是否使用过 ,0代表没使用,1代表已使用

给id加上索引

CREATE TABLE `member_index` (
  `id` int(6) NOT NULL ,
  `member_code` varchar(2) NOT NULL ,
  PRIMARY KEY (`id`),
  UNIQUE KEY `index` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

然后写了2个存储过程 用来初始化 数据库

第一个先用来插入10W条数据 ,将带有4的数字设置为已使用

BEGIN
    -- 从游标中取出的变量存放处
    DECLARE a INT;
    -- 循环99999的i
    DECLARE i INT;
    SET i = 1;
    -- 开始循环(循环到99999)
    my_loop : LOOP
      -- 判断个位数,十位,百位千万位是否为4
      IF i%10=4||(i%100/10>=4&&i%100/10<5)||(i%1000/100>=4&&i%1000/100<5)||(i%10000/1000>=4&&i%10000/1000<5)||(i/10000>=4&&i/10000<5) THEN
        INSERT INTO member_index VALUES (i,'1');
        ELSE
         INSERT INTO member_index VALUES (i,'0');
      END IF ;
      SET i = i+1;
      IF i>99999
        THEN
        LEAVE my_loop;
        END IF ;
    END LOOP ;
  END

一个用来将已经使用的id同步到 这个序列表中

BEGIN
    -- 从游标中取出的变量存放处
    DECLARE a VARCHAR(32);
    -- 遍历数据结束标志
    DECLARE done INT DEFAULT FALSE;
    -- 定义游标
    DECLARE cc CURSOR FOR SELECT member_code FROM member;
    -- 将结束标志绑定到游标
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = TRUE;
    -- 打开游标
    OPEN cc;
   -- 开始循环
    read_loop: LOOP
      -- 提取游标里的数据,这里只有一个,多个的话也一样;
      FETCH cc INTO a;
      -- 声明结束的时候
      IF done THEN
        LEAVE read_loop;
      END IF;
      -- 循环的修改事件
      UPDATE member_index set member_code = '1' where id = cast(a AS SIGNED INTEGER);
    END LOOP;
  -- 关闭游标
  CLOSE cc;
END

等待执行完初始化后,生成编号就很容易了

SQL如下

SELECT id FROM member_index WHERE member_code='0' limit 1;

0.26秒 ,一次查询就能拿到结果

似乎是这样没错,可感觉还是慢了点

用explain检查一下

果然,原来是没用上序列,立马修改了一下

EXPLAIN SELECT id FROM member_index WHERE member_code='0' ORDER BY id ASC limit 1;

查询速度进一步提升

一行超人 0.04s

完美的优化,开心

你可能感兴趣的:(MySql)