写点什么

【YashanDB 知识库】oracle dblink varchar 类型查询报错记录

作者:YashanDB
  • 2024-07-17
    广东
  • 本文字数:3821 字

    阅读完需:约 13 分钟

问题单:Oracle DBLINK 查询崖山 DB 报错

oracle 服务器上 ODBC 安装

unixodbc 安装:yum -y install unixODBC

mysql

配置安装对应版本的 odbc


myodbc-installer -d -a -n "MySQL8.0" -t "DRIVER=/home/oracle/tools/mysql-connector-odbc-8.0.20/lib/libmyodbc8w.so;SETUP=/home/oracle/tools/mysql-connector-odbc-8.0.20/lib/myodbc8S.so"

yashandb

安装 yasdb-odbc


安装 yasdb-client


配置 odbc 驱动:


sudo vi /etc/odbcinst.ini[YashanDB] Description=ODBC for yashanDBDriver=/home/oracle/xp/yashandb-odbc/libyas_odbc.soSetup=/home/oracle/xp/yashandb-odbc/libyas_odbc.soDriver64=/home/oracle/xp/yashandb-odbc/libyas_odbc.soSetup64=/home/oracle/xp/yashandb-odbc/libyas_odbc.so FileUsage=1 [ODBC]Trace=NO/YES #yes打开odbc日志TraceFile=/home/oracle/xp/odbc.log
复制代码


添加环境变量:


vi .bashrcexport LD_LIBRARY_PATH=​LD_LIBRARY_PATH:/home/oracle/xp/yashandb-odbc
复制代码

配置数据源

sudo vi /etc/odbc.ini[YASDBODBC]Description = YASODBCDriver = YashanDBSERVER = 192.168.18.207 PORT = 8688USER = sysPWD = yasdb_123 [MYSQLDB]Description = MySQL ODBC 5.0 Unicode DriverDriver = MySQL8.0Server = 192.168.7.134Database = zabbixPort = 3306USER = zabbixPassword = 123456Option = 3CHARSET = UTF8
复制代码

配置 oracle dblink 环境

监听文件配置

/data/app/oracle/product/19.3/dbhome_1/network/admin


vi listener.ora


新增:


SID_LIST_LISTENER =(SID_LIST =(SID_DESC =(SID_NAME = YASDBODBC)(ORACLE_HOME = /data/app/oracle/product/19.3/dbhome_1)(PROGRAM = dg4odbc)))SID_LIST_LISTENER =(SID_LIST =(SID_DESC =(SID_NAME = MYSQLDB)(ORACLE_HOME = /data/app/oracle/product/19.3/dbhome_1)(PROGRAM = dg4odbc)))
复制代码


坑 1:


配置这个后,oracle 的远程连接报错。


修改如下:


listener.ora 有三个部分


详解各个属性:


1、LISTENER 部分包含协议地址列表,每个实例一个入口,监听名称,可以配置多个监听,多个监听的端口号要区分开来


2、SID_LIST_LISTENER 部分标识全局数据库名称、标识监听程序正在服务的每个实例的 Oracle 软件主目录以及实例或 SID。


3、SID_LIST 描述用于静态数据库注册、保持和以前的版本兼容性以及供 Oracle Enterprise Manager 使用,因为我本地有三个数据库


把 SID_DESC 放到 SID_LIST_LISTENER 中


SID_LIST_LISTENER =  (SID_LIST =    (SID_DESC =      (GLOBAL_DBNAME = oracledb)      (ORACLE_HOME = /data/app/oracle/product/19.3/dbhome_1)      (SID_NAME = oracledb)    )         (SID_DESC =      (SID_NAME = YASDBODBC)      (ORACLE_HOME = /data/app/oracle/product/19.3/dbhome_1)      (PROGRAM = dg4odbc)    )         (SID_DESC =      (SID_NAME = MYSQLDB)      (ORACLE_HOME = /data/app/oracle/product/19.3/dbhome_1)      (PROGRAM = dg4odbc)    )  )
复制代码

配置 tns 文件

vi tnsnames.ora


新增:


YASDBODBC =(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.7.134)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = YASDBODBC))(HS = OK))MYSQLDB =(DESCRIPTION =(ADDRESS_LIST =(ADDRESS = (PROTOCOL = TCP)(HOST = 192.168.7.134)(PORT = 1521)))(CONNECT_DATA =(SERVICE_NAME = MYSQLDB))(HS = OK))
复制代码

配置 odbc 监听

cd /data/app/oracle/product/19.3/dbhome_1/hs/admin


mysql


添加文件:


touch initMYSQLDB.oravim initMYSQLDB.ora HS_FDS_CONNECT_INFO = MYSQLDBHS_FDS_TRACE_LEVEL = debugHS_FDS_SHAREABLE_NAME = /usr/lib64/libodbc.soHS_LANGUAGE = AMERICAN_AMERICA.US7ASCIIHS_NLS_NCHAR = UCS2#HS_FDS_SUPPORT_STATISTICS = FALSE set ODBCINI= /etc/odbc.ini
复制代码


yashandb


touch initYASDBODBC.oravim initYASDBODBC.ora HS_FDS_CONNECT_INFO = YASDBODBCHS_FDS_TRACE_LEVEL = debugHS_FDS_SHAREABLE_NAME = /usr/lib64/libodbc.soHS_LANGUAGE = AMERICAN_AMERICA.US7ASCIIHS_NLS_NCHAR = UCS2#HS_FDS_SUPPORT_STATISTICS = FALSE set ODBCINI= /etc/odbc.ini
复制代码

重启监听

lsnrctl stoplsnrctl startlsnrctl status
复制代码

创建链接异构数据库连接

在 yashandb 和 mysql 上建表如下:


drop table T1;create table T1(c1 varchar(2001) ,c2 int,c3 double);insert into T1 values('book1',51,1),('book2',22,2),('book3',66,3),(NULL,71,4),('book4',NULL,5);
复制代码


mysql


drop database link TEST_MYSQL;create database link TEST_MYSQL connect to "zabbix" IDENTIFIED by "123456" using 'MYSQLDB' ; SELECT * FROM T1@TEST_MYSQL; SELECT * FROM T1@TEST_MYSQL where "c3"=1 ;SELECT * FROM T1@TEST_MYSQL where "c2"=51 ;SELECT * FROM T1@TEST_MYSQL where cast("c1" as varchar(200))='book1';
复制代码


yashandb


drop database link YASDBODBC_TEST;create database link YASDBODBC_TEST connect to "sys" identified by "yasdb_123" using 'YASDBODBC'; SELECT * FROM T1@YASDBODBC_TEST; SELECT * FROM T1@YASDBODBC_TEST where c1='book1';SELECT * FROM T1@YASDBODBC_TEST where c2=51 ;SELECT * FROM T1@YASDBODBC_TEST where c3=1 ;
复制代码

问题原因

dblink 使用 odbc 连接其它数据库,如 yashandb、mysql 等


● 把其它数据库的 varchar 类型会变成 oralce 中的 nvarchar2 类型,如下组图 1。


● nvarchar2 类型 2 个字节存储一个字符,超过 varchar(2000)的字段类型因为超过了 4000 个字节,在 oracle 中变成了 long 类型,如下组图 2。


● long 类型不能在 where、group by、order by 中使用。

问题复现

组图 1


mysql 中的表类型:



oracle 中的表类型:



查询正常:



组图 2


mysql 中的表类型:



oracle 中的表类型:



查询报错:


oracle long 类型限制

  • LONG 数据类型中存储的是可变长字符串,最大长度限制是 2GB。

  • 对于超出一定长度的文本,基本只能用 LONG 类型来存储,数据字典中很多对象的定义就是用 LONG 来存储的。

  • LONG 类型主要用于不需要作字符串搜索的长串数据,如果要进行字符搜索就要用 varchar2 类型。

  • 很多工具,包括 SQLPlus,处理 LONG 数据类型都是很困难的。

  • LONG 数据类型的使用中,要受限于磁盘的大小。


能够操作 LONG 的 SQL 语句:


  • Select 语句

  • Update 语句中的 SET 语句

  • Insert 语句中的 VALUES 语句


限制:


  • 一个表中只能包含一个 LONG 类型的列。

  • 不能索引 LONG 类型列。

  • 不能将含有 LONG 类型列的表作聚簇。

  • 不能在 SQLPlus 中将 LONG 类型列的数值插入到另一个表格中,如 insert into …select。

  • 不能在 SQL*Plus 中通过查询其他表的方式来创建 LONG 类型列,如 create table as select。

  • 不能对 LONG 类型列加约束条件(NULL、NOT NULL、DEFAULT 除外),如:关键字列(PRIMARY KEY)不能是 LONG 数据类型。

  • LONG 类型列不能用在 Select 的以下子句中:where、group by、order by,以及带有 distinct 的 select 语句中。

  • LONG 类型列不能用于分布查询。

  • PL/SQL 过程块的变量不能定义为 LONG 类型。

  • LONG 类型列不能被 SQL 函数所改变,如:substr、instr。 因为 long 类型的数值不能用 insert into … select 的方法插入,故我们要分两步走,先插入其它字段,最后再插入 long 类型字段,这可以通过过程来实现.


参考:oracle里long类型的总结_oracle long-CSDN博客

char 类型区别

char


1、char 的长度是固定的。比如说,你定义了 char(20),即使你你插入 abc,不足二十个字节,数据库也会在 abc 后面自动加上 17 个空格,以补足二十个字节;


2、char 是区分中英文的。中文在 char 中占两个字节,而英文占一个,所以 char(20)你只能存 20 个字母或 10 个汉字。


char 适用于长度比较固定的,一般不含中文的情况。


varchar/varchar2


1、varchar 是长度不固定的。比如说,你定义了 varchar(20),当你插入 abc,则在数据库中只占 3 个字节。


2、varchar 同样区分中英文。这点同 char。


3、varchar2 基本上等同于 varchar。它是 oracle 自己定义的一个非工业标准 varchar,不同在于,varchar2 用 null 代替 varchar 的空字符串。


varchar/varchar2 适用于长度不固定的,一般不含中文的情况。


nvarchar/nvarchar2


1、nvarchar 和 nvarchar2 是长度不固定的;


2、nvarchar 不区分中英文。比如说:你定义了 nvarchar(20),你可以存入 20 个英文字母/汉字或中英文组合,这个 20 定义的是字符数而不是字节数;


3、nvarchar2 基本上等同于 nvarchar,不同在于 nvarchar2 中存的英文字母也占两个字节。


大多数情况下,ORACLE 中的国家字符集是默认的,以下结论成立:


如果要省存储空间,建表时,字段内容里如果中文占了大多数,就用 nvarchar2 类型;如果内容是英文和数字为主的字符串,就用 varchar2 类型。


注意:


  • ORACLE 中的国家字符集,只有在数据类型为 NCHAR/NVARCHAR/NCLOB 时才会被使用,也就是前面带 N(national)的字符类型;

  • ORACLE 默认国家字符集为 AL16UTF16,完全对应 UNICODE 的 UTF-16 标准(有别于数据库字符集)

  • ORACLE 中的 UTF-8,不是标准的 UTF-8,而是 CESU-8。


参考:Oracle字段类型char、varchar2、nvarchar2的区别与使用_oracle varchar2-CSDN博客

规避方法

varchar 最大支持长度为 4000 字节,通过参数 MAX_STRING_SIZE 控制 MAX_STRING_SIZE 默认为 STANDARD,修改成 EXTENDED 支持 32K


修改步骤:


sql> shutdown immediate;sql> startup upgrade;sql> alter system set max_string_size=EXTENDED scope=both;sql> @?/rdbms/admin/utl32k.sqlsql> startup;sql> @?/rdbms/admin/utlrp.sql
复制代码


用户头像

YashanDB

关注

全自研国产新型大数据管理系统 2022-02-15 加入

还未添加个人简介

评论

发布
暂无评论
【YashanDB知识库】oracle dblink varchar类型查询报错记录_yashandb_YashanDB_InfoQ写作社区