LIKE 是 SQL 模糊比對的核心運算子,配合通配符 % (任意長度)、_ (單字元) 實現前綴、後綴、包含、單字元匹配。本文系統講解語法、大小寫敏感度、中文編碼坑、索引使用條件、效能優化與 PHP 參數化查詢實戰。
| 模式 | 含義 | 範例匹配 |
|---|---|---|
'abc%' | 以 abc 開頭 | abc, abcd, abcdef |
'%abc' | 以 abc 結尾 | abc, zabc, 123abc |
'%abc%' | 包含 abc | abc, zabc, abcxyz, 1abc2 |
'_abc' | 單字元 + abc | zabc, 1abc (不匹配 abc) |
'a_c' | a + 單字元 + c | abc, axc (不匹配 ac、abxc) |
'abc' | 精確等值 (等同 =) | 僅 abc |
CHAR、VARCHAR、TEXT):依**排序規則**決定。utf8mb4_general_ci、utf8mb4_unicode_ci → **不區分大小寫**。utf8mb4_bin、latin1_bin → **區分大小寫**。BINARY、VARBINARY、BLOB):永遠區分大小寫。SELECT * FROM user WHERE username LIKE BINARY '%Admin%'; -- 僅匹配 Admin SELECT * FROM user WHERE username COLLATE utf8mb4_bin LIKE '%Admin%'; -- 同效
SELECT * FROM user WHERE username COLLATE utf8mb4_general_ci LIKE '%admin%';
utf8mb4_general_ci,但連線字元集設為 latin1 或 gbk → 位元組序列錯位,導致 LIKE '%中文%' 匹配到錯誤位元組組合。SET NAMES utf8mb4 (連線)、CHARSET=utf8mb4 (表/庫)、COLLATE=utf8mb4_general_ci (欄位)。SELECT * FROM user WHERE username LIKE BINARY CONCAT('%', '中文', '%');SELECT * FROM user WHERE UPPER(username) LIKE BINARY CONCAT('%', UPPER('a中文b'), '%');| 模式 | 能否用索引 | 存取類型 |
|---|---|---|
'abc%' | ✅ 是 | range (索引範圍掃描) |
'%abc' | ❌ 否 | ALL (全表掃描) |
'%abc%' | ❌ 否 | ALL |
'_abc%' | ❌ 否 (MySQL 8.0.0+ 部分優化) | ALL |
**原理**:B+樹索引按字典序排序,前綴固定才能定位範圍;前導通配符無法定位起始點。
LIKE 'keyword%'。FULLTEXT INDEX + MATCH() AGAINST() (MySQL 5.6+ 支援中文 ngram parser)。LIKE 'prefix_%' 仍可用索引。%...%**;必要時加 LIMIT、縮小掃描範圍 (WHERE id > 10000 AND col LIKE '%x%')。$pdo = new PDO('mysql:host=127.0.0.1;dbname=test;charset=utf8mb4', 'user', 'pass', [
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
PDO::ATTR_EMULATE_PREPARES => false, // 真正預處理
]);
$keyword = 'admin';
$stmt = $pdo->prepare('SELECT id, username FROM user WHERE username LIKE ?');
$stmt->execute(["%{$keyword}%"]); // 通配符在 PHP 端拼接,而非 SQL 端
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
echo "ID: {$row['id']}, User: {$row['username']}\n";
}
$mysqli = new mysqli('127.0.0.1', 'user', 'pass', 'test');
$mysqli->set_charset('utf8mb4');
$keyword = 'admin';
$stmt = $mysqli->prepare('SELECT id, username FROM user WHERE username LIKE ?');
$like = "%{$keyword}%";
$stmt->bind_param('s', $like);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_assoc()) {
echo "ID: {$row['id']}, User: {$row['username']}\n";
}
%、_ 在 PHP 端拼接,傳入完整模式字串給 ? 佔位符。%、_ 需按字面匹配,需轉義:str_replace(['%', '_'], ['\\%', '\\_'], $input)。| 現象 | 原因 | 解決 |
|---|---|---|
LIKE '%關鍵字%' 極慢 | 全表掃描,無索引 | 改用 FULLTEXT、或業務改前綴、或縮小掃描範圍 |
| 中文匹配不到 | 連線字元集與儲存編碼不一致 | 統一 SET NAMES utf8mb4、表/欄位 utf8mb4 |
| 大小寫不符合預期 | 排序規則 _ci vs _bin | 用 BINARY 或 COLLATE 顯式指定 |
| 索引明明存在但不用 | 模式以 % 開頭、或隱式轉換 | 改寫模式、檢查 EXPLAIN 型別轉換警告 |
結語: LIKE 雖簡單,但編碼、排序規則、索引匹配規則暗藏玄機。掌握「前綴用索引、中文統一 UTF8MB4、大小寫顯式控制、參數化防注入」,即能寫出正確且高效的模糊查詢。