PHP 按月分表控制台命令(yii2版)
<?php /** * @Purpose: 按月分表腳本 * @User: Chrdai * @Date: 2019/3/19 * @Time: 15:23 */ namespace app\commands; use yii\console\Controller; class CreateTableController extends Controller { /** * @var string 數據庫服務器 */
const HOST = '127.0.0.1'; /** * @var string 用戶名 */
const USERNAME = 'root'; /** * @var string 密碼 */
const PASSWORD = 'testpasswd'; /** * @var string 數據庫 */
const DBNAME = 'test'; /** * @var string 默認方法 */
public $defaultAction = 'create-table-by-month'; public function options($actionID) { return parent::options($actionID); } /** * @purpose: 准備表前綴和表結構 * @author: Chrdai * @time: 2019-03-19 * @return array */
public function prepare() { $userPrefix = 'user_'; $userSql = <<<EOF ( id int(11) NOT NULL AUTO_INCREMENT, name varchar(32) NOT NULL DEFAULT '' COMMENT '姓名', created_at datetime DEFAULT CURRENT_TIMESTAMP COMMENT '創建時間', updated_at datetime DEFAULT null COMMENT '更新時間', PRIMARY KEY (id) ) CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT '用戶表'; EOF; return [ [ 'table_prefix' => $userPrefix,
'sql' => $userSql, ], ]; } /** * @purpose: 如果網絡可用,則進行一次時間同步 * @author: Chrdai * @time: 2019-03-19 */
public function updateToCurrentTime() { //ping 3 次
passthru('ping baidu.com -c 3 >/dev/null 2>&1',$res); if($res === 0){ system('ntpdate asia.pool.ntp.org && hwclock --systohc'); } } /** * @purpose: 按月分表 * #表命名方案:table_prefix_年月_序號 * #每月的表1是保存1---15日的數據,表2是保存16--31日的數據 * @author: Chrdai * @time: 2019-03-19 */
public function actionCreateTableByMonth() { //登錄mysql
$mysqlLoginInfo = '-h'.self::HOST.' -u'.self::USERNAME.' -p'.self::PASSWORD . ' -D'.self::DBNAME; $createHead = "CREATE TABLE IF NOT EXISTS "; $this->updateToCurrentTime(); $arrTable = $this->prepare(); $year = date('Y',time()); $month = date('m',time()); // 創建本月的表
foreach($arrTable as $val){ //每月2張表
for($i = 1; $i <=2 ; $i ++){ $tableName = $val['table_prefix'] . $year . $month . '_' . $i; $sql = end($val); system("/usr/bin/mysql {$mysqlLoginInfo} -e \"{$createHead} {$tableName} {$sql}\""); } } //創建下個月的表,如果跨年需要單獨處理
if(intval($month) == 12){ $nextYear = $year + 1; foreach($arrTable as $val){ for($i = 1; $i <=2 ; $i ++){ //下一年1月份的表名
$tableName = $val['table_prefix'] . $nextYear . '01_' . $i; $sql = end($val); system("/usr/bin/mysql {$mysqlLoginInfo} -e \"{$createHead} {$tableName} {$sql}\""); } } }else{ $nextMonth = intval($month) + 1; //下個月的表名
$fullMonth = $nextMonth < 10 ? '0' . $nextMonth : $nextMonth; foreach($arrTable as $val){ for($i = 1; $i <=2 ; $i ++){ $tableName = $val['table_prefix'] . $year . $fullMonth . '_' . $i; $sql = end($val); system("/usr/bin/mysql {$mysqlLoginInfo} -e \"{$createHead} {$tableName} {$sql}\""); } } } } }
分表規則為:
每月分兩張表.
1-15號為 table_prefix_Ym_1 ,
16-31號為table_prefix_Ym_2 ,
如:table_prefix_201903_1
<?php /** * @purpose: 根據時間范圍獲取表名 * @explain: 表名的分表規則是,每月分兩張表,1-15號為 table_prefix_Ym_1 ,16-31號為table_prefix_2 , 如:table_prefix_201903_1 * User: Chrdai * Date: 2019/3/5 * Time: 18:08 */
class TablePrefix { /** * @const app調用記錄表前綴 */
const PREFIX= 'table_prefix_'; /** * @purpose:獲取指定時間范圍內的app調用記錄表 * @param int|string $starttime 開始時間 * @param int|string $endtime 結束時間 * @return array $tables 指定時間范圍內的應用程序記錄表 */
public static function getTableByDateRange($starttime,$endtime) { $tables = []; if(!empty($starttime)){ $start = is_numeric($starttime) ? date('Ymd',$starttime) : date('Ymd',strtotime($starttime)); } if(!empty($endtime)){ $end = is_numeric($endtime) ? date('Ymd',$endtime) : date('Ymd',strtotime($endtime)); } if(!empty($start) && !empty($end)){ $prev = floor($start / 100); $next = floor($end / 100); //開始時間小於等於結束時間范圍內的表都房間$tables
while ($prev <= $next){ $tables[] = self::PREFIX . $prev. '_1'; $tables[] = self::PREFIX . $prev. '_2'; $prev = ($prev % 100 === 12) ? ((floor($prev/100) + 1) * 100 +1) : $prev + 1; //對誇年的月份做特殊處理
} //以15天為分界線,分上下月,去除重復的表
if($start % 100 > 15){ array_shift($tables); } if($end % 100 <= 15){ array_pop($tables); } } return $tables; } }
//獲取表名
$tables = TablePrefix::getTableByDateRange('2019-03-05 12:00:00','2019-03-05 14:00:00'); //循環處理各個表中的數據
$table = array_shift($tables); // 首先拿出第一張表中的數據
while(true){ __loop:
//...... (每張表的業務邏輯) // 如果$tables中沒有表了,則跳出循環,否則循環處理
if(empty($tables)){ break; }else{ $table = array_shift($tables); goto __loop; } }
此文為袋鼠(Chrdai)工作中所幾記,如有轉載請注明出處:https://www.cnblogs.com/chrdai/p/10551175.html