1

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

问题描述及要求:

第1部分 :

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

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

关于 JSON 搜索索引:

JSON 搜索索引是一种专门针对 JSON 数据的全文索引。优化器仅在数据库使用AL32UTF8 或 WE8ISO8859P1 字符集时才考虑使用索引,并且仅适用于 VARCHAR2、BLOB 或 CLOB 列中的 JSON 数据,而不是 NVARCHAR2 和 NCLOB 列

第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?')

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

如 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');
4

1 回答 1

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'));
于 2019-12-05T07:54:50.703 回答