暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

【干货攻略】达梦报错超长记录如何分析

达梦E学 2024-11-29
221

引 言

在达梦数据库上,有时候在做数据库移植或应用开发测试过程中会遇到“记录超长”的错误。报错“记录超长”字面意思很好理解,但是跟哪些因素有关呢?

这个报错其实根据字面意思我们大概知道是数据的长度超长,对达梦数据库比较熟悉的使用者其实是知道该如何处理的,一般来说有以下两种方法:

1、重新初始化实例,设置更大的页大小。

2、对报错的表开启超长记录。

下面我们通过举例来讨论这个记录超长的具体原因并进行分析,分析过程中我们要提到以下几个概念:

  • 页大小(page_size)
  • 超长记录
  • 行内数据与行外数据
  • 配置参数LOB_MAX_INROW_LEN
本章内容已在如下环境上测试:
①数据库版本:达梦DM8。
相关关键字:记录超长 ,-2665

——正文——

01

页大小

页大小是初始化数据库时的参数,会影响字符长度(如char/varchar)的实际最大值和每条记录的最大长度。例如:
第一,当页大小为8K时,对于字符类型实际最大长度为3900字节(不同页大小影响字符类型实际的最大长度是不一样的,见下图所示)。
第二,行内记录长度最大长度不超过页大小的一半,这个是大前提。
了解这两个前提对于理解以下内容比较关键,为了方便说明问题,我们使用默认的页大小page_size=8K。
举个例子:
    create table test_singlecol( col varchar(8000));
    insert into test_singlecol values(repeat('a',4000)); --报错,因为超过3900了
    insert into test_singlecol values(repeat('a',3880)); --报错,因为超过3900了
    insert into test_singlecol values(repeat('a',3879)); --正常插入,还有20个自己被内置的存储占用,例如伪列rowid,trxid还有null标记等
    复制
    插入4000报错可以理解,因为超过8k页的约3900的限制了,那为什么3880页报错了?其实我们知道达梦数据库中会有两个伪列,ROWID和TRXID,分别来看一下这两个伪列的长度:
      select lengthb(rowid),lengthb(trxid),* from dual;
      复制

      这里我们可以大概算一下,除此之外,varchar类型由于是变长类型,且实际数据长度大于128,还需要2个字节表示长度,所以3880+20+2=3902>3900报错了。

      02

      超长记录

      假如我们就是需要插入超过限制的大小,我们可以开启超长记录,那么就可以解除这个限制,因为超长的记录以blob的形式存在了行外。
      超长记录存储功能是指当 DM 行存储的记录长度超过页大小一半时,是否尝试将过长的变长字符串转换为行外 BLOB 存储。
        ALTER TABLE test_singlecol ENABLE USING LONG ROW;
        insert into test_singlecol values(repeat('a',3880)); --正常插入
        insert into test_singlecol values(repeat('a',4000)); --正常插入
        复制

        在基表中,当没有指定 USING LONG ROW 存储选项时,插入 VARCHAR 数据类型的实际最大存储长度由数据库页面大小决定,如果指定了 USING LONG ROW 存储选项,则插入 VARCHAR 数据类型的长度不受数据库页面大小限制。VARCHAR 类型在表达式计算中的长度上限不受页面大小限制,为 32767;

        03

        行内数据与行外数据

        对于像TEXT、CLOB之类的大字段类型而言,当实际数据长度较小时就与其他字段紧凑的放在一起,称之为行内数据,如果实际数据长度较长时,实际数据就单独放在某些数据页中,而与其他字段一起存储的只是大字段头。
          drop table if exists test_text;
          create table test_text(col text);
          insert into test_text values(repeat('a',901));
          commit;
          select dump(col) from test_text;
          复制

          可以看到行内行外标记为行外,而行内长度为47,这个47也就是大字段头的长度。
          因为我们知道记录一旦超长被记录到行外lob中,则行内字段记录的是这个数据的大字段头信息,是固定长度47。
          对比如下两种插入:
          对于varchar类型表定义:
            call create_table(39,'varchar(4000)');
            call insert_table(39,4000);-- -2665: 记录超长
            alter table "SYSDBA"."TEST_39COL" enable using long row;
            call insert_table(39,4000);--正常插入
            对于text类型表定义:
            drop table if exists TEST_39COL;
            call create_table(39,'text');
            call insert_table(39,50);-- 正常插入,行内
            call insert_table(39,100);-- 正常插入,行外
            call insert_table(39,4000);-- 正常插入,行外
            select dump(c1),dump(c2),dump(c3),dump(c4) from TEST_39COL;
            复制

            对比可以看出对于varchar类型定义的表,超长记录不会自动存储到行外,除非开启超长记录。而lob类型定义的表,会根据实际数据长度自动决定存储在行内还是行外,当然这里对于lob类型的数据,是否存在行内由参数LOB_MAX_INROW_LEN来控制。

            04

            LOB类型行内存储最大长度

            LOB_MAX_INROW_LEN默认为900,决定了大字段类型能放进行行内存储的最大长度(但并不绝对,还与“每条记录总长度不超过页大小一般”有关),与上述讨论的第三点息息相关,超过该值则作为行外存储,没超过则作为行内存储。
              select * from v$dm_ini where para_name like 'LOB%';
              复制

                create table test_lob(col text);
                insert into test_lob values(repeat('a',901));--行外
                insert into test_lob values(repeat('a',900));--行内
                commit;
                select dump(col) from test_lob;
                复制

                可以看到,改参数值可以控制是否存在行内的边界长度。那回到上述第三点讨论中,这个插入的varchar长度是100,并没有超过LOB_MAX_INROW_LEN默认值,为什么也是存在行外呢?这里我们可以大致计算一下,如果这条记录存在行内的话39*100+20=3920,也超过了3900所以只能存到行外去了。

                总结


                综上所述,达梦数据库中报错“记录超长”与上述因素都有关系,其中页大小是影响最大的一个因素,如果业务场景中涉及的表都会比较“宽”,那么建议直接将页大小设置大一些,可以避免一些记录超长的问题,但是相对来说也会更加浪费空间一些,这里需要dba做一些权衡。



                END


                以上为本期分享,希望能带给大家帮助。想要了解更多往期干货,可访问页面最下方#达梦技术干货攻略#合集或下方相关分享。在此邀请更多学员参与“达梦技术干货投稿活动”,稿件获选后将在达梦“干货分享”专栏进行发布,欢迎来稿!


                往期回顾


                【干货攻略】SQL优化之-LIKE CASE WHEN改写思路

                【干货攻略】DM8在线重定义表

                【干货攻略】DM8获取SQL历史执行计划

                开班通知】第35期DM8-DCP线上培训班招生中

                【开班通知】第37期DM8-DCA线上培训班招生中



                达梦E学
                达梦数据  学习园地


                文章转载自达梦E学,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                评论