溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

MySQL分表自增ID問(wèn)題的解決方法

發(fā)布時(shí)間:2021-08-12 10:14:04 來(lái)源:億速云 閱讀:336 作者:chen 欄目:MySQL數(shù)據(jù)庫(kù)

這篇文章主要講解了“MySQL分表自增ID問(wèn)題的解決方法”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“MySQL分表自增ID問(wèn)題的解決方法”吧!

當(dāng)我們對(duì)MySQL進(jìn)行分表操作后,將不能依賴(lài)MySQL的自動(dòng)增量來(lái)產(chǎn)生唯一ID了,因?yàn)閿?shù)據(jù)已經(jīng)分散到多個(gè)表中?! ?/p>

應(yīng)盡量避免使用自增IP來(lái)做為主鍵,為數(shù)據(jù)庫(kù)分表操作帶來(lái)極大的不便。

在postgreSQL、oracle、db2數(shù)據(jù)庫(kù)中有一個(gè)特殊的特性---sequence。 任何時(shí)候數(shù)據(jù)庫(kù)可以根據(jù)當(dāng)前表中的記錄數(shù)大小和步長(zhǎng)來(lái)獲取到該表下一條記錄數(shù)。然而,MySQL是沒(méi)有這種序列對(duì)象的。

可以通過(guò)下面的方法來(lái)實(shí)現(xiàn)sequence特性產(chǎn)生唯一ID:
1. 通過(guò)MySQL表生成ID
對(duì)于插入也就是insert操作,首先就是獲取唯一的id了,就需要一個(gè)表來(lái)專(zhuān)門(mén)創(chuàng)建id,插入一條記錄,并獲取最后插入的ID。代碼如下:

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

也就是說(shuō),當(dāng)我們需要插入數(shù)據(jù)的時(shí)候,必須由這個(gè)表來(lái)產(chǎn)生id值,我的php代碼的方法如下:

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

這種方法效果很好,但是在高并發(fā)情況下,MySQL的AUTO_INCREMENT將導(dǎo)致整個(gè)數(shù)據(jù)庫(kù)慢。如果存在自增字段,MySQL會(huì)維護(hù)一個(gè)自增 鎖,innodb會(huì)在內(nèi)存里保存一個(gè)計(jì)數(shù)器來(lái)記錄auto_increment值,當(dāng)插入一個(gè)新行數(shù)據(jù)時(shí),就會(huì)用一個(gè)表鎖來(lái)鎖住這個(gè)計(jì)數(shù)器,直到插入結(jié) 束。如果是一行一行的插入是沒(méi)有問(wèn)題的,但是在高并發(fā)情況下,那就悲催了,表鎖會(huì)引起SQL阻塞,極大的影響性能,還可能會(huì)達(dá)到 max_connections值。
innodb_autoinc_lock_mode:可以設(shè)定3個(gè)值:0、1、2
0:traditonal (每次都會(huì)產(chǎn)生表鎖)
1:consecutive (默認(rèn),可預(yù)判行數(shù)時(shí)使用新方式,不可時(shí)使用表鎖,對(duì)于simple insert會(huì)獲得批量的鎖,保證連續(xù)插入)
2:interleaved (不會(huì)鎖表,來(lái)一個(gè)處理一個(gè),并發(fā)最高)
對(duì)于myisam表引擎是traditional,每次都會(huì)進(jìn)行表鎖的。

2. 通過(guò)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. 隊(duì)列方式

其實(shí)這也算是上面的一個(gè)解說(shuō)
使用隊(duì)列服務(wù),如redis、memcacheq等等,將一定量的ID預(yù)分配在一個(gè)隊(duì)列里,每次插入操作,先從隊(duì)列中獲取一個(gè)ID,若插入失敗的話,將該ID再次添加到隊(duì)列中,同時(shí)監(jiān)控隊(duì)列數(shù)量,當(dāng)小于閥值時(shí),自動(dòng)向隊(duì)列中添加元素。

這種方式可以有規(guī)劃的對(duì)ID進(jìn)行分配,還會(huì)帶來(lái)經(jīng)濟(jì)效應(yīng),比如QQ號(hào)碼,各種靚號(hào),明碼標(biāo)價(jià)。如網(wǎng)站的userid, 允許uid登陸,推出各種靚號(hào),明碼標(biāo)價(jià),對(duì)于普通的ID打亂后再隨機(jī)分配。

<?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());

監(jiān)控隊(duì)列數(shù)量,并自動(dòng)補(bǔ)充隊(duì)列和取到id但并沒(méi)有使用

感謝各位的閱讀,以上就是“MySQL分表自增ID問(wèn)題的解決方法”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)MySQL分表自增ID問(wèn)題的解決方法這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI