在单字节Oracle环境中进行多字节字符存储(在BLOB中)和搜索(使用JSON函数)

时间:2019-11-25 10:38:00

标签: json oracle oracle12c multibyte-characters

详细信息: Oracle数据库12c, 数据库版本:12.1.0.2.0

问题描述和要求:

第1部分:

  1. 我在NCLOB列中存储了JSON数据。
  2. 我需要从JSON数据中搜索文本。
  3. 考虑到性能,我可以选择使用数据类型BLOB,因为数据是JSON,并且在BLOB列中。我可以使用JSON索引全文搜索。

使用BLOB列上的JSON文本搜索索引进行搜索时,与NCLOB上的简单查询(LIKE)相比,性能得到了显着提高。

关于JSON搜索索引:

JSON搜索索引是一种专门用于JSON数据的全文本索引。 如果数据库使用字符集AL32UTF8或WE8ISO8859P1 ,并且仅针对VARCHAR2,BLOB或CLOB列中的JSON数据,而不使用NVARCHAR2和NCLOB列,则优化器将仅考虑使用索引。 / strong>。

第2部分:

我们有两种数据库类型,即单字节和多字节部署

单个字节的字符集:

NLS_NCHAR_CHARACTERSET ---> AL16UTF16, NLS_CHARACTERSET ---------> WE8MSWIN1252

多字节字符集:

NLS_NCHAR_CHARACTERSET ---> AL16UTF16, NLS_CHARACTERSET ---------> AL32UTF8

第3部分:

在多字节部署中,我能够存储和搜索(使用JSON_TEXTCONTAINS)多字节文本,例如'məharaːʂʈrə'。 原因:因为数据库使用字符集AL32UTF8(BLOB列) 注意:JSON_TEXTCONTAINS仅适用于索引。

在单字节部署中,我无法存储相同的文本,即“məharaːʂʈrə”(由于它是多字节,因此转换会导致数据丢失,例如“ m?hara ??? r?”)

问题: 如何在具有字符集WE8MSWIN1252的单字节部署的BLOB列中存储多字节数据,即“məharaːʂʈrə”。

如oracle所述:如果数据库使用 AL32UTF8或WE8ISO8859P1字符集,则优化器将仅考虑使用索引。 请注意,我也可以在单字节环境中使用JSON搜索索引,即JSON_TEXTCONTAINS(用于简单搜索,即单字节)。

一旦我能够按原样存储数据,就可以使用JSON_TEXTCONTAINS进行搜索。

示例代码(在单字节和多字节部署中都尝试: 请注意:https://livesql.oracle.com/是多字节部署。

创建表:

create table departments_json (
  department_id   integer not null primary key,
  department_data blob not null
);

数据应为严格的Json(因此我们可以使用点符号进行遍历):

alter table departments_json
  add constraint dept_data_json 
  check ( department_data is JSON FORMAT JSON STRICT );

创建索引:

create index deptj_ctx_ix 
  on departments_json (department_data)
    indextype is ctxsys.context     parameters ('section group  CTXSYS.JSON_SECTION_GROUP  sync (on commit)');

插入简单的json

insert into departments_json 
  values ( 140, utl_raw.cast_to_raw ('{"department_list":[{"Deptname":"DEPT-A", "value" : "məharaːʂʈrə"}]}'));

如果有任何错误(以单字节为单位),请将其转换:

insert into departments_json 
  values ( 140, UTL_RAW.convert(utl_raw.cast_to_raw ('{"department_list":[{"Deptname":"DEPT-A", "value" : "məharaːʂʈrə"}]}'),'AL32UTF8','WE8MSWIN1252'));

存储的值:

SELECT json_value(department_data format json, '$.department_list.value'  ) FROM departments_json JS WHERE DEPARTMENT_ID=140;

观察:在单字节环境中将导致数据丢失。

现在搜索:

SELECT *
FROM   departments_json
WHERE JSON_TEXTCONTAINS(department_data,  '$.department_list.value', 'məharaːʂʈrə');

观察:多字节将导致行,而单字节将导致无行。

还可以在单​​字节环境中使用JSON搜索索引,即JSON_TEXTCONTAINS(用于简单搜索,即单字节)-在查询结果下方一行:

SELECT *
FROM   departments_json
WHERE JSON_TEXTCONTAINS(department_data,  '$.department_list.Deptname', 'DEPT-A');

1 个答案:

答案 0 :(得分:0)

您可以通过.NET(C#)保存数据:

System.Text.Encoding.RegisterProvider(System.Text.CodePagesEncodingProvider.Instance);
var value = System.Text.Encoding.GetEncoding("windows-1252").GetString(System.Text.Encoding.UTF8.GetBytes("məharaːʂʈrə"));
string h = "{\"department_list\":[{\"Deptname\":\"DEPT-A\", \"value\" : \"" + value + "\"}]}";
var byteArraySource = System.Text.Encoding.Unicode.GetBytes(h);
byte[] byteArray = System.Text.Encoding.Convert(System.Text.Encoding.Unicode, 
System.Text.Encoding.UTF8, byteArraySource);
using (var orclCon = new Oracle.ManagedDataAccess.Client.OracleConnection(connectionString))
{
    orclCon.Open();
    var cmd = orclCon.CreateCommand();
    cmd.CommandType = System.Data.CommandType.Text;
    cmd.CommandText = "insert into departments_jsonvalues (140, :paramValue)";
    cmd.Parameters.Add(new Oracle.ManagedDataAccess.Client.OracleParameter("paramValue", Oracle.ManagedDataAccess.Client.OracleDbType.Blob, byteArray, System.Data.ParameterDirection.Input));
    cmd.ExecuteNonQuery();
}

对于.NET中的搜索结果:

string h ="məharaːʂʈrə";    
var read_command = orclCon.CreateCommand();
read_command.CommandType = System.Data.CommandType.Text;
read_command.Parameters.Add(new Oracle.ManagedDataAccess.Client.OracleParameter("searchText", System.Text.Encoding.GetEncoding("windows-1252").GetString(System.Text.Encoding.UTF8.GetBytes(h))));
read_command.CommandText = "select * from departments_json JSON_TEXTCONTAINS(department_data,  '$.department_list.value', :searchText)";
var dr = read_command.ExecuteReader();
using (dr)
{
  if (dr.HasRows)
  {
    while (dr.Read())
    {
      Oracle.ManagedDataAccess.Types.OracleBlob BLOB = dr.GetOracleBlob(1);
      var sr = new System.IO.StreamReader(BLOB);
      var content = sr.ReadToEnd();
    }
  }
}

插入SQL:

insert into departments_json values (140, utl_raw.cast_to_raw ('{"department_list":[{"Deptname":"DEPT-A", "value" :'|| UTL_RAW.convert("məharaːʂʈrə",'UTF8','WE8MSWIN1252')||'}]}'));

SQL搜索结果:

SELECT * FROM   departments_json WHERE JSON_TEXTCONTAINS(department_data, '$.department_list.value', CONVERT('məharaːʂʈrə', 'UTF8', 'WE8MSWIN1252'));