thinkPHP5中分表的使用以及內置方法的分析

前言

首先,我們要知道什麼是分表?以及我們爲什麼要分表?以及分表有哪些方式?我們根據不同的業務場景應該怎樣去分表?在thinkPHP5框架裏面我們又該怎麼操作。

分表的意義

大家都知道mysql數據庫是小型數據庫,每張表最大承受的數據量大約是1億條,而每張表超過300萬條數據,單張表的查詢速率會受到影響。(這個數值更具每張表的數據結構和數據值不同而變化。這裏只是一個估值)
這個時候我們解決的辦法之一就是:分表。
那麼分表,通常又分爲橫向分表(水平分表),和縱向分表(垂直分表)。從字面上的意思理解的話,橫向分表就是將數據量很大的表按照我們的業務需求,設定規則,水平切割成多張表。縱向分表就比較簡單,通常是指一張表的數據字段太多,爲了避免單表數據量太大,以及查看時候太過雜亂,將它的部分數據字段切割到其他表中。
我們這裏說的分表,主要是指橫向分表。

thinkPHP5裏面進行分表

1. 常規操作
我們理解了分表的意義和規則。接下來就很好操作。我們先不用thinkPHP裏面的函數,來對分表的數據表進行操作。
假設場景:交易流水的業務數據量很大,我們對交易流水錶進行按照月份進行分表。

首先,我們使用定時任務,在每年的12月份,定時生成下一年的12張(按月份)交易流水數據表。可能是這樣的格式:
trade_log_202001, trade_log_202002, trade_log_202003, trade_log_202004…trade_log_202012
表已經建好了。

接下來就是對錶中的數據進行操作。
我們可以封裝一個方法:獲取當前條件的交易數據表。
然後再使用的時候調用這個方法,就是我們要操作的數據表。
thinkPHP 裏面可以使用 setTable 方法設置修改模型中的數據表。
然後進行操作就可以了。
如果是原生的sql查詢也是一樣的

2. 分析thinkPHP5源碼中的方法

先把源碼貼出來,直接在源碼裏面一行行解釋把。

   /**
     * 設置分表規則
     * @access public
     * @param array  $data  操作的數據
     * @param string $field 分表依據的字段
     * @param array  $rule  分表規則
     * @return $this
     */
	//  註釋: 這是要分表操作調用方法,主要是獲取分表的表名,並設置它。
    public function partition($data, $field, $rule = [])
    {
        $this->options['table'] = $this->getPartitionTableName($data, $field, $rule);
        return $this;
    }
    
	/**
     * 得到分表的的數據表名
     * @access public
     * @param array  $data  操作的數據
     * @param string $field 分表依據的字段
     * @param array  $rule  分表規則
     * @return string
     */
	// 註釋:這個是分表的重點函數,主要是根據傳入的參數獲取分表表名
	// rule 裏面的expr就是每張表規定的數量,num就是表的數量,即分了幾張表。
    public function getPartitionTableName($data, $field, $rule = [])
    {
        // 對數據表進行分區
        // 註釋: 這塊判斷,如果設置了分表字段,並且傳入了分表規則字段,走下面的流程
        // 否則,直接聯合查詢多張表。查出數據(走else查多張表,分表還有什麼意義?)
        if ($field && isset($data[$field])) {
            $value = $data[$field];
            $type  = $rule['type'];
            switch ($type) {
                case 'id':  //就是根據id來分,我們必須在rule裏面設置expr。
                    // 按照id範圍分表
                    $step = $rule['expr'];
                    $seq  = floor($value / $step) + 1; //分表後綴就是當前數據id除步進值加1
                    break;
                case 'year':
                    // 按照年份分表
                    if (!is_numeric($value)) {
                        $value = strtotime($value);
                    }
                    $seq = date('Y', $value) - $rule['expr'] + 1;
                    break;
                case 'mod':
                    // 按照id的模數分表
                    $seq = ($value % $rule['num']) + 1; //取模+1。
                    break;
                case 'md5':
                    // 按照md5的序列分表
                    $seq = (ord(substr(md5($value), 0, 1)) % $rule['num']) + 1; // 我們必須設置要分幾張表
                    break;
                default:
                    if (function_exists($type)) { // 固定函數hash,也可重寫這部分,自定義規則,實現自定義設置後綴
                        // 支持指定函數哈希 //ord函數:獲取字符串的ASCII碼
                        $seq = (ord(substr($type($value), 0, 1)) % $rule['num']) + 1;
                    } else {
                        // 按照字段的首字母的值分表  //$value{0}這種寫法是獲取字符串$value的第0個字符。
                        $seq = (ord($value{0}) % $rule['num']) + 1;
                    }
            }
            return $this->getTable() . '_' . $seq; // 返回表名。
        } else { // 聯合查詢了,不推薦這種操作。
            // 當設置的分表字段不在查詢條件或者數據中
            // 進行聯合查詢,必須設定 partition['num']
            $tableName = [];
            for ($i = 0; $i < $rule['num']; $i++) {
                $tableName[] = 'SELECT * FROM ' . $this->getTable() . '_' . ($i + 1);
            }

            $tableName = '( ' . implode(" UNION ", $tableName) . ') AS ' . $this->name;
            return $tableName;
        }
    }

解釋完了,是不是感覺很簡單?就這!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章