當一個表數據記錄過大時就會出現性能瓶頸,而一般對應的解決辦法是要麼做分區表,要麼分表,分區表就不說了,分表又分為垂直分割和水平分割,具體區別請自行搜索。一般而言,分庫分表屬於水平分割,按照一定的規則將數據插入到不同的表中去。而分庫則可以很方便的轉移數據庫的壓力,比如將一個很大庫的分別放在不同的服務器上。
下面是我寫的一個分庫分表的實現:
namespace App\Model\Database; class Config { public $dsn; public $user; public $password; /** * @var string 分庫分表後得到的數據庫名 */ public $dbname; /** * @var string 分庫分表後得到的表名 */ public $table; /** * @var array MySQL 配置數組 */ private static $config; /** * @var string 配置文件路徑 */ private static $configFile = 'mysql.php'; public function __construct($dbname, $table, $id = 0) { if (is_null(static::$config)) { $config = include(static::$configFile); static::$config = $config; } $config = static::$config; if (isset($config['shared']) && isset($config['shared'][$dbname])) { $dbconfig = $config['shared'][$dbname]; $id = is_numeric($id) ? (int)$id : crc32($id); $database_id = ($id / $dbconfig['database_split'][0]) % $dbconfig['database_split'][1]; $table_id = ($id / $dbconfig['table_split'][0]) % $dbconfig['table_split'][1]; foreach ($dbconfig['host'] as $key => $conf) { list($from, $to) = explode('-', $key); if ($from <= $database_id && $database_id <= $to) { $the_config = $conf; } } $this->dbname = $dbname . '_' . $database_id; $this->table = $table . '_' . $table_id; } else { $this->dbname = $dbname; $this->table = $table; $the_config = $config['db'][$dbname]; } $c = $the_config; if (isset($c['unix_socket']) && $c['unix_socket']) { $this->dsn = sprintf('mysql:dbname=%s;unix_socket=%s', $this->dbname, $c['unix_socket']); } else { $this->dsn = sprintf('mysql:dbname=%s;host=%s;port=%s', $this->dbname, $c['host'], $c['port']); } $this->user = $c['user']; $this->password = $c['password']; } }
$default = array( 'unix_socket' => null, 'host' => 'localhost', 'port' => '3306', 'user' => 'root', 'password' => '', ); $config = array( // 不進行分庫分表的數據庫 'db' => array( 'my_site' => $default, ), // 分庫分表 'shared' => array( 'user' => array( 'host' => array( /** * 編號為 0 到 10 的庫使用的鏈接配置 */ '0-10' => $default, /** * 編號為 11 到 28 的庫使用的鏈接配置 */ '11-28' => $default, /** * 編號為 29 到 99 的庫使用的鏈接配置 */ '29-99' => $default, ), // 分庫分表規則 /** * 下面的配置對應百庫百表 * 如果根據 uid 進行分表,假設 uid 為 543234678,對應的庫表為: * (543234678 / 1) % 100 = 78 為編號為 78 的庫 * (543234678 / 100) % 100 = 46 為編號為 46 的表 */ 'database_split' => array(1, 100), 'table_split' => array(100, 100), ), ), ); return $config;
namespace App\Model; use App\Model\Database\Config; use \PDO; abstract class Model { /** * @var Config */ public $config; /** * @var PDO */ public $connection; protected $dbnamePrefix; protected $tablePrefix; /** * @var string 分庫分表後對應的表 */ protected $table; public function __construct($id) { $this->config = new Config($this->dbnamePrefix, $this->tablePrefix, $id); $this->connection = new Pdo($this->config->dsn, $this->config->user, $this->config->password); $this->table = $this->config->table; } public function update(array $data, array $where = array()) { } public function select(array $where) { } public function insert(array $data) { } public function query($sql) { return $this->connection->query($sql); } }
require 'Config.php'; require 'Model.php'; use App\Model\Model; class User extends Model { protected $dbnamePrefix = 'user'; protected $tablePrefix = 'userinfo'; } $user = new User(4455345345); print_r($user);