在Navicat“索引”选项卡建复合唯一索引,需右键表→设计表→索引页→点“+”→填索引名→在字段列表中逐行添加多列(如第一行token、第二行user_id)→类型选UNIQUE→确认两行均已指定列名并保存。
Navicat 里“索引”选项卡怎么选多列建复合唯一索引
直接在“索引”选项卡里勾多个字段,不是靠 ctrl/shift 多选——navicat 的索引字段列表是**可拖拽排序的多行表格**,每行对应一个索引列。要建复合唯一索引,必须把所有参与列按顺序逐行添加进去。
常见错误是只填第一列、点保存,结果建出来的是单列唯一索引;或者误以为勾“唯一”复选框就能自动覆盖全部字段,其实它只作用于当前索引定义整体。
- 右键表 → “设计表” → 切到
索引选项卡 - 点左下角
+(或“添加索引”)→ 填索引名(如uk_token_user_id) - 在下方字段列表中:第一行选
token,第二行选user_id(顺序不能反,影响最左前缀匹配) -
类型下拉菜单选UNIQUE(不是勾“唯一”复选框) - 保存前确认:字段列表里已有两行、且都已指定列名
为什么建完复合唯一索引后 INSERT IGNORE 还不生效
根本原因常被忽略:MySQL 对 INSERT IGNORE 或 ON DUPLICATE KEY UPDATE 的触发,依赖的是 **KEY 名称匹配**,而 Navicat 自动生成的复合唯一索引名可能不符合 MySQL 的隐式命名规则(比如含空格或特殊字符),导致语句找不到对应 KEY。
更稳妥的做法是显式命名并验证:
- 用 SQL 手动建:
ALTER TABLE tb_device_user ADD UNIQUE KEY uk_token_user_id (token, user_id); - 执行后立刻查:
SHOW CREATE TABLE tb_device_user;,确认输出里有UNIQUE KEY `uk_token_user_id` (`token`,`user_id`) - 再试
INSERT IGNORE INTO tb_device_user (token, user_id, user_pwd) VALUES ('t1', 100, 'pwd1');
如果仍不生效,大概率是字段值本身含不可见字符(如开头空格)、或 token 和 user_id 其中一列允许 NULL ——MySQL 认为 NULL != NULL,所以两条 (NULL, 1) 不算重复。
Navicat 图形界面建的复合唯一索引,在 PostgreSQL 里查不到约束名
PostgreSQL 把唯一约束底层实现为唯一索引,所以它不会出现在 pg_constraint 的约束列表里,而是归在索引节点下。你用 Navicat 图形化建的 UNIQUE 索引,本质就是 CREATE UNIQUE INDEX,不是 ADD CONSTRAINT。
验证方式必须用:
SELECT indexname, indexdef FROM pg_indexes WHERE tablename = 'tb_device_user';
如果返回里 indexdef 含 UNIQUE 且字段顺序一致,说明已生效。想让它出现在约束视图里,得改用 SQL:ALTER TABLE tb_device_user ADD CONSTRAINT uk_token_user_id UNIQUE (token, user_id);
注意:Navicat 的图形操作对 PostgreSQL 和 MySQL 的抽象逻辑不同,同一套 UI 操作,背后生成的 DDL 可能完全不同。
复合唯一索引建完,为什么 SELECT 还没走索引
索引建了 ≠ 查询自动用。MySQL 是否走复合索引,严格依赖 WHERE 条件是否满足最左前缀原则。
- 索引是
(token, user_id),WHERE token = 'x'会走;WHERE user_id = 100不会 -
WHERE token = 'x' AND user_id > 50只能用上token部分,user_id无法做范围扫描 - 字段类型要严格匹配:如果
token是VARCHAR(32),但查询时传了CHAR字面量,可能触发隐式转换,导致索引失效
用 EXPLAIN 看 key 列是否显示你的索引名,比看 Navicat 界面里的绿色对勾靠谱得多。











