MySQL分表自增ID問題的解決方案_Mysql

來源:互聯網
上載者:User

當我們對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但並沒有使用

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.