MySQL分表自增ID问题的解决方法

 更新时间:2016年06月12日 12:10:12   作者:郑宏鑫erke  
这篇文章主要为大家详细介绍了MySQL分表自增ID问题的解决方法,感兴趣的小伙伴们可以参考一下

当我们对MySQL进行分表操作后,将不能依赖MySQL的自动增量来产生唯一ID了,因为数据已经分散到多个表中。  
 应尽量避免使用自增IP来做为主键,为数据库分表操作带来极大的不便。
 在postgreSQL、oracle、db2数据库中有一个特殊的特性---sequence。 任何时候数据库可以根据当前表中的记录数大小和步长来获取到该表下一条记录数。然而,MySQL是没有这种序列对象的。
 可以通过下面的方法来实现sequence特性产生唯一ID:

 1. 通过MySQL表生成ID
 对于插入也就是insert操作,首先就是获取唯一的id了,就需要一个表来专门创建id,插入一条记录,并获取最后插入的ID。代码如下: 

CREATE TABLE `ttlsa_com`.`create_id` ( 
`id` BIGINT( 20 ) NOT NULL AUTO_INCREMENT PRIMARY KEY
) ENGINE = MYISAM 

 也就是说,当我们需要插入数据的时候,必须由这个表来产生id值,我的php代码的方法如下:

<?php 
function get_AI_ID() { 
 $sql = "insert into create_id (id) values('')"; 
 $this->db->query($sql); 
 return $this->db->insertID(); 
} 
?> 

这种方法效果很好,但是在高并发情况下,MySQL的AUTO_INCREMENT将导致整个数据库慢。如果存在自增字段,MySQL会维护一个自增 锁,innodb会在内存里保存一个计数器来记录auto_increment值,当插入一个新行数据时,就会用一个表锁来锁住这个计数器,直到插入结 束。如果是一行一行的插入是没有问题的,但是在高并发情况下,那就悲催了,表锁会引起SQL阻塞,极大的影响性能,还可能会达到 max_connections值。
 innodb_autoinc_lock_mode:可以设定3个值:0、1、2
 0:traditonal (每次都会产生表锁)
 1:consecutive (默认,可预判行数时使用新方式,不可时使用表锁,对于simple insert会获得批量的锁,保证连续插入)
 2:interleaved (不会锁表,来一个处理一个,并发最高)
 对于myisam表引擎是traditional,每次都会进行表锁的。 

2. 通过redis生成ID 

function get_next_autoincrement_waitlock($timeout = 60){
 $count = $timeout > 0 ? $timeout : 60;
 
 while($r->get("serial:lock")){
 $count++;
 sleep(1);
 if ($count > 10)
 return false;
 }
 
 return true;
}
 
function get_next_autoincrement($timeout = 60){
 // first check if we are locked...
 if (get_next_autoincrement_waitlock($timeout) == false)
 return 0;
 
 $id = $r->incr("serial");
 
 if ( $id > 1 )
 return $id;
 
 // if ID == 1, we assume we do not have "serial" key...
 
 // first we need to get lock.
 if ($r->setnx("serial:lock"), 1){
 $r->expire("serial:lock", 60 * 5);
 
 // get max(id) from database.
 $id = select_db_query("select max(id) from user_posts");
 // or alternatively:
 // select id from user_posts order by id desc limit 1
 
 // increase it
 $id++;
 
 // update Redis key
 $r->set("serial", $id);
 
 // release the lock
 $r->del("serial:lock");
 
 return $id;
 }
 
 // can not get lock.
 return 0;
}
 
$r = new Redis();
$r->connect("127.0.0.1", "6379");
 
$id = get_next_autoincrement();
if ($id){
  $sql = "insert into user_posts(id,user,message)values($id,'$user','$message')"
  $data = exec_db_query($sql);
}

3. 队列方式
 其实这也算是上面的一个解说
 使用队列服务,如redis、memcacheq等等,将一定量的ID预分配在一个队列里,每次插入操作,先从队列中获取一个ID,若插入失败的话,将该ID再次添加到队列中,同时监控队列数量,当小于阀值时,自动向队列中添加元素。
 这种方式可以有规划的对ID进行分配,还会带来经济效应,比如QQ号码,各种靓号,明码标价。如网站的userid, 允许uid登陆,推出各种靓号,明码标价,对于普通的ID打乱后再随机分配。

<?php
 
class common {
 
 private $r;
 
 function construct() {
  $this->__construct();
 }
 
 public function __construct(){
  $this->r=new Redis();
  $this->r->connect('127.0.0.1', 6379);
 }
 
 function set_queue_id($ids){
  if(is_array($ids) && isset($ids)){
  foreach ($ids as $id){
  $this->r->LPUSH('next_autoincrement',$id);
  }
  }
 }
 
 function get_next_autoincrement(){
  return $this->r->LPOP('next_autoincrement');
 }
 
}
 
$createid=array();
while(count($createid)<20){
 $num=rand(1000,4000);
 if(!in_array($num,$createid))
  $createid[]=$num;
}
 
$id=new common();
$id->set_queue_id($createid);
 
var_dump($id->get_next_autoincrement()); 

监控队列数量,并自动补充队列和取到id但并没有使用

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • CentOS6.9下mysql 5.7.17安装配置方法图文教程

    CentOS6.9下mysql 5.7.17安装配置方法图文教程

    这篇文章主要为大家详细介绍了CentOS6.9下mysql 5.7.17安装配置方法图文教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-10-10
  • Mysql导入导出时遇到的问题解决

    Mysql导入导出时遇到的问题解决

    这篇文章主要给大家介绍了关于Mysql导入导出时遇到问题的解决方法,文中通过示例代码介绍的非常详细,对大家学习或者使用Mysql具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-08-08
  • Window环境下MySQL UDF提权

    Window环境下MySQL UDF提权

    本文章仅记录某次内网渗透过程中遇到的MySQL 采用UDF提权等方式进行获取权限,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧<BR>
    2023-03-03
  • MySQL普通索引和唯一索引的深入讲解

    MySQL普通索引和唯一索引的深入讲解

    这篇文章主要给大家介绍了关于MySQL普通索引和唯一索引的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-01-01
  • MySQL通过DQL实现对数据库数据的条件查询

    MySQL通过DQL实现对数据库数据的条件查询

    这篇文章给大家介绍了MySQL如何通过DQL进行数据库数据的条件查询,文中通过代码示例和图文结合介绍的非常详细,对大家的学习或工作有一定的帮助,需要的朋友可以参考下
    2024-01-01
  • mysql 实现互换表中两列数据方法简单实例

    mysql 实现互换表中两列数据方法简单实例

    这篇文章主要介绍了mysql 实现互换表中两列数据方法简单实例的相关资料,需要的朋友可以参考下
    2016-10-10
  • 深入理解MySQL重做日志 redo log

    深入理解MySQL重做日志 redo log

    redo log:被称为物理日志,记录的就是最终修改后的按页面存储的数据页,直接存数据最终的状态,用于确保事务的持久性,本文主要介绍了MySQL重做日志 redo log,感兴趣的了解一下
    2022-04-04
  • mysql中文排序注意事项与实现方法

    mysql中文排序注意事项与实现方法

    mysql在查询字符串时是大小写不敏感的,在编绎mysql时一般以ISO-8859字符集作为默认的字符集,因此在比较过程中中文编码字符大小写转换造成了这种现象,比较应急的方法是对于包含中文的字段加上"binary"属性,使之作二进制比较
    2008-09-09
  • Mysql大表添加字段失败问题及解决

    Mysql大表添加字段失败问题及解决

    这篇文章主要介绍了Mysql大表添加字段失败问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-04-04
  • mysql5.7.18安装并修改初始密码的方法

    mysql5.7.18安装并修改初始密码的方法

    这篇文章主要为大家详细介绍了Mysql5.7安装并修改初始密码的方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-06-06

最新评论