首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

資料庫欄位複用技巧:位元運算實現多狀態單欄位儲存

     編輯:PHP 相關知識

核心概念:位元遮罩

利用整數的二進位位元,將多個獨立的布林/枚舉狀態壓縮儲存於單一 INT UNSIGNED 欄位。透過位元 AND(&)查詢、位元 OR(|)設定、位元 XOR(^)切換,實現極高效能的多屬性索引與過濾。

邏輯代數基礎

運算符號真值表助記
AND&1&1=1, 其餘=0「全 1 才 1」,如同乘法
OR|0|0=0, 其餘=1「有 1 即 1」,如同加法
NOT~0→1, 1→0翻轉位元

欄位定義範例:users.status INT UNSIGNED NOT NULL DEFAULT 0

位元分配(從低位到高位):

位元區間用途值定義遮罩
0-2 (3 bits)註冊狀態0=未審, 1=通過, 2=高級, 3=管理, 4=超管0b111 = 7
3-5 (3 bits)性別0=未知, 1=男, 2=女0b111000 = 56
6-8會員等級0=普通, 1=銀, 2=金, 3=鑽0b111000000 = 448
9-31保留擴充——

PHP 常數定義與查詢建構

<?php
// 狀態常數
define('USER_NEW',      0b000);   // 0
define('USER_NORMAL',   0b001);   // 1
define('USER_ADVANCE',  0b010);   // 2
define('USER_MANAGE',   0b011);   // 3
define('USER_SUPER',    0b100);   // 4
define('USER_MASK',     0b111);   // 7

define('GENDER_UNKNOWN', 0b000000); // 0
define('GENDER_MALE',    0b001000); // 8  (1 << 3)
define('GENDER_FEMALE',  0b010000); // 16 (2 << 3)
define('GENDER_MASK',    0b111000); // 56

// 查詢建構函式
function buildWhere(int $status, int $mask): string {
    return "(`status` & $mask) = $status";
}

// 使用範例
$sql = "SELECT * FROM users WHERE " . buildWhere(GENDER_MALE, GENDER_MASK);
// → SELECT * FROM users WHERE (status & 56) = 8

$sql = "SELECT * FROM users WHERE " . buildWhere(USER_MANAGE, USER_MASK);
// → SELECT * FROM users WHERE (status & 7) = 3

// 組合條件:男性且為管理員
$combinedStatus = GENDER_MALE | USER_MANAGE; // 8 | 3 = 11
$combinedMask   = GENDER_MASK | USER_MASK;   // 56 | 7 = 63
$sql = "SELECT * FROM users WHERE " . buildWhere($combinedStatus, $combinedMask);
// → (status & 63) = 11

// 排除條件:非「未審核」
$sql = "SELECT * FROM users WHERE (status & " . USER_MASK . ") != " . USER_NEW;
?>

位元操作封裝 Trait(可複用於 Model)

<?php
trait BitwiseFlags {
    protected int $flags = 0;

    public function hasFlag(int $mask, int $value = null): bool {
        if ($value === null) return ($this->flags & $mask) !== 0;
        return ($this->flags & $mask) === $value;
    }

    public function setFlag(int $mask, int $value): self {
        $this->flags = ($this->flags & ~$mask) | ($value & $mask);
        return $this;
    }

    public function toggleFlag(int $mask): self {
        $this->flags ^= $mask;
        return $this;
    }

    public function getRawFlags(): int {
        return $this->flags;
    }
}

// 使用
class User {
    use BitwiseFlags;
    // ...
}
$user = new User();
$user->setFlag(GENDER_MASK, GENDER_MALE)
     ->setFlag(USER_MASK, USER_MANAGE);
echo $user->hasFlag(GENDER_MASK, GENDER_MALE); // true
?>

優缺點分析

優點缺點
單欄位儲存多屬性,節省結構修改成本語義隱含於程式碼常數,DB 直接看不懂
位元運算極快,索引友善(status & mask = val 可用索引)單一屬性值域受限於位元寬度(3 bits 只能 0-7)
組合查詢單一 WHERE 條件,減少 JOIN需嚴格管理常數定義,避免位元衝突
新增屬性只需分配新位元區,無 ALTER TABLE不適用於高基數屬性(如標籤、分類)

適用場景判斷

  • ✅ 低基數、固定枚舉、頻繁組合過濾:用戶狀態、權限標記、商品屬性標籤(上架/推薦/新品/熱賣)
  • ❌ 高基數、動態增減、需人工閱讀:文章標籤、商品分類、地址層級

總結

位元遮罩是關聯式資料庫中實現「欄位複用」的經典技巧,配合 PHP 位元運算子與常數定義,能以極低儲存成本支援高效能的多維度查詢。關鍵在於嚴謹的位元規劃、集中管理常數、封裝操作介面,避免硬編碼散落導致維護災難。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved