MySQL ERROR 1709 (HY000)

本文介绍了解决MySQL中因字段过大导致无法建立索引的问题。通过调整配置及使用row_format=DYNAMIC来支持更大的字段索引。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


创建一张表,其中有个varchar 大字段,并且在这个字段上建索引,结果发现MySQL报错:

ERROR 1709 (HY000): Index column size too large. The maximum column size is 767 bytes.


以下为建表语句:

create table piratebay(
SYS_ID		int ,
FILE_NAME	VARCHAR(200),
FILE_ID		VARCHAR(30),
NUM1		VARCHAR(30),
NUM2		VARCHAR(30),
MAGNET_LINK	VARCHAR(500),
PRIMARY KEY	(sys_id),
KEY 		piratebay_n1 (FILE_NAME)) 
engine=innodb;

MySQL 环境配置:

Server version: 5.6.28-log MySQL Community Server (GPL)

Server characterset: utf8mb4
Db       characterset: utf8mb4


解决办法:

(1)查看相关配置并作出如下设置

innodb_large_prefix = ON 
innodb_file_format = Barracuda 
innodb_file_per_table = ON 

(2)修改建表语句,加入 row_format=DYNAMIC

create table piratebay(
SYS_ID		int ,
FILE_NAME	VARCHAR(200),
FILE_ID		VARCHAR(30),
NUM1		VARCHAR(30),
NUM2		VARCHAR(30),
MAGNET_LINK	VARCHAR(500),
PRIMARY KEY	(sys_id),
KEY 		piratebay_n1 (FILE_NAME)) 
engine=innodb row_format=dynamic;


原因:

       MySQL 索引只支持767个字节,utf8mb4 每个字符占用4个字节,所以索引最大长度只能为191个字符,即varchar(191),若想要使用更大的字段,mysql需要设置成支持数据压缩,并且修改表属性 row_format ={DYNAMIC|COMPRESSED}

官方解释:

https://dev.mysql.com/doc/refman/5.5/en/innodb-parameters.html#sysvar_innodb_large_prefix



<think>我们正在处理MySQL递归查询超限错误(ERROR 3636 HY000)。这个错误通常发生在使用递归公用表表达式(CTE)时,递归层数超过了系统默认的最大递归深度(1000层)。解决方案包括调整最大递归深度或优化查询。 参考信息:MySQL官方文档提到,可以通过设置cte_max_recursion_depth系统变量来增加递归深度限制。该变量默认值为1000,最大可设置为4294967295。 步骤: 1. 临时调整会话级别的递归深度限制(例如设为10000): ```sql SET SESSION cte_max_recursion_depth = 10000; ``` 然后再次运行递归查询。 2. 如果问题仍然存在,可能需要永久修改该变量(在配置文件中设置): 在my.cnf(或my.ini)文件中添加: ``` [mysqld] cte_max_recursion_depth=10000 ``` 然后重启MySQL服务。 3. 优化递归查询:如果递归深度确实很大,考虑是否可以优化查询逻辑,减少递归层数。例如,检查递归结束条件是否合理,避免无限递归。 4. 如果递归深度无法减少,且调整递归深度限制不可行(例如,由于系统资源限制),可能需要考虑使用存储过程或迭代方式替代递归CTE。 注意:设置过大的递归深度可能导致内存消耗过大,因此需要谨慎。 下面是一个简单的递归CTE示例,用于生成数字序列(如果序列长度超过默认递归深度,则会出现相同错误): ```sql WITH RECURSIVE cte (n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM cte WHERE n < 10000 ) SELECT * FROM cte; ``` 此时,如果递归深度限制为1000,则执行到第1001次时会报错。通过设置cte_max_recursion_depth为10000,即可解决。 另外,还可以在查询中通过提示(hint)来设置本次查询的最大递归深度(MySQL 8.0.19及以上版本支持): ```sql WITH RECURSIVE cte (n) AS ( SELECT 1 UNION ALL SELECT n + 1 FROM cte WHERE n < 10000 ) SELECT /*+ SET_VAR(cte_max_recursion_depth = 10000) */ * FROM cte; ``` 引用说明:MySQL官方文档中关于递归CTE的限制和设置,请参考[^1]。 如果上述方法仍不能解决问题,可能需要检查递归查询是否存在逻辑错误导致无限循环(例如,递归部分没有正确终止条件)。可以通过在递归部分添加条件来避免无限递归。 另外,还可以通过设置最大执行时间(max_execution_time)来避免查询长时间运行,但这不会解决递归深度问题。 总结:解决ERROR 3636的主要方法是增加递归深度限制或优化查询。 相关问题: 1. 如何检查MySQL当前递归深度限制? 2. 如何避免递归CTE的无限循环? 3. 递归查询在MySQL中有哪些替代方案? 4. 如何监控递归查询的内存使用情况? [^1]: MySQL官方文档:https://dev.mysql.com/doc/refman/8.0/en/server-system-variables.html#sysvar_cte_max_recursion_depth</think>### MySQL递归查询超限错误解决方案(ERROR 3636 HY000) 当MySQL递归查询超过默认深度限制时,会出现`ERROR 3636 (HY000): Recursive query aborted after 1001 iterations`错误。以下是完整的解决方案: #### 1. **调整递归深度限制(推荐)** 默认递归深度为1000层,可通过系统变量修改: ```sql -- 临时修改(当前会话有效) SET SESSION cte_max_recursion_depth = 10000; -- 设为10000层 -- 永久修改(需重启服务) SET GLOBAL cte_max_recursion_depth = 10000; ``` 或在`my.cnf`配置文件中添加: ```ini [mysqld] cte_max_recursion_depth=10000 ``` #### 2. **查询级深度覆盖(MySQL 8.0.19+)** 在递归查询中直接指定深度限制: ```sql WITH RECURSIVE cte AS ( SELECT /*+ SET_VAR(cte_max_recursion_depth = 5000) */ ... ) SELECT ... ``` #### 3. **优化递归查询逻辑** 检查并修复可能导致无限递归的逻辑错误: ```sql WITH RECURSIVE org_tree AS ( SELECT id, parent_id, name FROM organization WHERE parent_id IS NULL -- 确保有终止条件 UNION ALL SELECT o.id, o.parent_id, o.name FROM organization o INNER JOIN org_tree ot ON o.parent_id = ot.id WHERE o.id <> ot.id -- 防止父子循环引用 ) SELECT * FROM org_tree; ``` #### 4. **替代方案:存储过程** 当递归层级极深时,改用存储过程: ```sql DELIMITER // CREATE PROCEDURE GetTree(IN root_id INT) BEGIN DROP TEMPORARY TABLE IF EXISTS tmp_tree; CREATE TEMPORARY TABLE tmp_tree (id INT PRIMARY KEY, depth INT); INSERT INTO tmp_tree VALUES (root_id, 0); WHILE ROW_COUNT() > 0 DO INSERT INTO tmp_tree SELECT o.id, MAX(t.depth)+1 FROM organization o JOIN tmp_tree t ON o.parent_id = t.id WHERE NOT EXISTS (SELECT 1 FROM tmp_tree WHERE id = o.id); END WHILE; SELECT * FROM tmp_tree; END // DELIMITER ; CALL GetTree(1); -- 从根节点ID=1开始 ``` #### 5. **深度监控与预警** 查询当前递归深度: ```sql SELECT ROW_NUMBER() OVER () AS depth, cte.* FROM ( WITH RECURSIVE cte AS (...) SELECT ... ) cte; ``` > **关键注意事项**: > 1. 深度值上限为`4294967295`,但过高可能导致内存溢出 > 2. 确保递归有终止条件(如`WHERE parent_id IS NOT NULL`) > 3. 循环引用检测:添加`WHERE NOT EXISTS (SELECT ...)`条件 > 4. 生产环境建议深度值不超过`100000`[^1] --- ### 递归查询示例(组织架构树) ```sql WITH RECURSIVE org_hierarchy AS ( SELECT id, name, parent_id, 0 AS depth, CAST(id AS CHAR(200)) AS path FROM organization WHERE parent_id IS NULL -- 根节点 UNION ALL SELECT o.id, o.name, o.parent_id, oh.depth + 1, CONCAT(oh.path, '->', o.id) FROM organization o JOIN org_hierarchy oh ON o.parent_id = oh.id WHERE oh.depth < 100 -- 安全深度限制 ) SELECT * FROM org_hierarchy; ``` --- ### 相关问题 1. 如何检测MySQL递归查询中的循环引用? 2. 递归CTE和存储过程处理树形结构各自的优缺点是什么? 3. 当递归深度超过10万层时,MySQL性能如何优化? 4. 如何实现递归查询的分页功能? 5. MySQL递归查询与图数据库(如Neo4j)处理层次结构的性能对比? [^1]: MySQL官方文档指出:递归深度设置需考虑可用内存,过高值可能导致服务器不稳定。建议根据`max_allowed_packet`和`thread_stack`配置调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值