Как правильно ограничить строку для VARCHAR2 (4000 БАЙТ) в Oracle?JAVA

Программисты JAVA общаются здесь
Ответить Пред. темаСлед. тема
Anonymous
 Как правильно ограничить строку для VARCHAR2 (4000 БАЙТ) в Oracle?

Сообщение Anonymous »

Мы используем столбцы VARCHAR2(4000 CHAR) в нашей базе данных Oracle для хранения данных JSON без слишком большого снижения производительности за счет использования CLOB. Я узнал, что 4000 CHAR технически ограничены 4000 BYTE, что является максимальной длиной для всех этих строковых столбцов. Даже NVARCHAR2 ограничен этими 4000 БАЙТ.
Вот почему мы пытаемся разделить наши строки на стороне Java кода на фрагменты по 4000 байт. Чтобы определить реальную длину строки в базе данных, мы используем String#getBytes(StandardCharsets.UTF_8).length. Кажется, это не работает надежно. Тем не менее Oracle иногда выдает следующую ошибку:

ORA-12899: Wert zu groß für Spalte
"OUR_DATABASE"."HISTORICAL_DATASETS"."JSON1" (актуэлл: 4006,
максимум: 4000)

Ораклом используется кодировка ALS32UTF8 – согласно SELECT параметр, значение ИЗ nls_database_parameters ГДЕ параметр LIKE 'NLS_CHARACTERSET'.
Что мне не хватает? Есть ли какие-либо дополнительные накладные расходы, несмотря на само кодирование?
РЕДАКТИРОВАТЬ: Вот используемый метод #split:
public static List split(String input, int size, boolean inBytes, Charset charset) {
List parts = new ArrayList();
StringBuilder segment = new StringBuilder();
int length = 0;

for (int i = 0; i < input.length(); i++) {
String c = input.substring(i, i+1); // charAt(i);

// Wie viele Bytes ein Zeichen ggf. wirklich beansprucht, hängt von der Codierung ab!
int realLength = inBytes ? c.getBytes(charset).length : 1;

if (realLength > size) throw new IllegalArgumentException("Der Parameter muss mindestens so groß sein," +
" dass jedes der Zeichen dort reinpasst! " + size +
" ist aktuell leider zu klein für " + realLength + " Bytes.");

// Wenn die aktuelle Länge das Limit überschreitet, speichern wir den aktuellen Teil.
if (length + realLength > size) {
parts.add(segment.toString());
segment = new StringBuilder();
length = 0;
}

segment.append(c);
length += realLength;
}

// Füge den letzten Teil hinzu, falls noch etwas übrig ist.
if (segment.length() > 0) {
parts.add(segment.toString());
}

return parts;
}

А это мой сеттер:
public void setJson(@NotNull String json) {
if (json.getBytes(StandardCharsets.UTF_8).length > 5 * MAX_VARCHAR) {
this.jsonShort1 = null;
this.jsonShort2 = null;
this.jsonShort3 = null;
this.jsonShort4 = null;
this.jsonShort5 = null;
this.jsonLong = json;
}
else {
List split = StringUtils.split(json, MAX_VARCHAR, true, StandardCharsets.UTF_8);
this.jsonShort1 = split.size() > 0 ? split.get(0) : null;
this.jsonShort2 = split.size() > 1 ? split.get(1) : null;
this.jsonShort3 = split.size() > 2 ? split.get(2) : null;
this.jsonShort4 = split.size() > 3 ? split.get(3) : null;
this.jsonShort5 = split.size() > 4 ? split.get(4) : null;
this.jsonLong = null;
}
}

Для следующих полей:
@Lob private String jsonLong;
@Column(length = MAX_VARCHAR) private String jsonShort1;
@Column(length = MAX_VARCHAR) private String jsonShort2;
@Column(length = MAX_VARCHAR) private String jsonShort3;
@Column(length = MAX_VARCHAR) private String jsonShort4;
@Column(length = MAX_VARCHAR) private String jsonShort5;

РЕДАКТИРОВАНИЕ № 2:
Здесь более подробная информация о разнице в производительности между CLOB и VARCHAR в моем случае. Использование локального образа Docker, на котором работает Oracle DB и локальный JBoss EAP.
Использование следующего быстрого и грязного API:
package my.test;

import my.model.HistoricalDataset;
import my.utils.LoremIpsum;

import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.transaction.Transactional;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import java.util.List;

@Path("/A1E-16094")
public class A1E_16094 {

@Inject private EntityManager em;

@GET
@Path("/generate")
@Produces("text/plain")
@Transactional
public String generate() {
long max = 0;
for (int i = 0; i < 50000; i++) {
String string = LoremIpsum.getWords(2000);
this.em.persist(HistoricalDataset.useVARCHAR(string));
this.em.persist(HistoricalDataset.useCLOB(string));
max = Math.max(max, string.length());
}
return "2x 50.000 EntityManager#persist() mit bis zu " + max + " Zeichen als VARCHAR + CLOB\n";
}

@GET
@Path("/loadVARCHAR")
@Produces("text/plain")
public String loadVARCHAR() {
List datasets = this.em.createQuery("from HistoricalDataset where uuidTable = 'VARCHAR'",
HistoricalDataset.class).getResultList();
return datasets.size() + " Datensätze mit VARCHAR geladen\n";
}

@GET
@Path("/loadCLOB")
@Produces("text/plain")
public String loadCLOB() {
List datasets = this.em.createQuery("from HistoricalDataset where uuidTable = 'CLOB'",
HistoricalDataset.class).getResultList();
return datasets.size() + " Datensätze mit CLOB geladen\n";
}

@GET
@Path("/delete")
@Produces("text/plain")
@Transactional
public String delete() {
int count = this.em.createQuery("delete from HistoricalDataset where uuidTable in ('CLOB', 'VARCHAR')")
.executeUpdate();
return count + " Datensätze mit VARCHAR + CLOB wieder gelöscht\n";
}
}

Вот мои результаты:
daniel@McPherson:./jboss-eap-7.4 $ curl -s -w "Zeit: %{time_total}s\n" http://localhost:8080/webapp/rest/A1E-16094/generate
2x 50.000 EntityManager#persist() mit bis zu 12452 Zeichen als VARCHAR + CLOB
Zeit: 97.379629s
daniel@McPherson:./jboss-eap-7.4 $ curl -s -w "Zeit: %{time_total}s\n" http://localhost:8080/webapp/rest/A1E-16094/loadVARCHAR
50000 Datensätze mit VARCHAR geladen
Zeit: 7.544128s
daniel@McPherson:./jboss-eap-7.4 $ curl -s -w "Zeit: %{time_total}s\n" http://localhost:8080/webapp/rest/A1E-16094/loadCLOB
50000 Datensätze mit CLOB geladen
Zeit: 43.838948s
daniel@McPherson:./jboss-eap-7.4 $ curl -s -w "Zeit: %{time_total}s\n" http://localhost:8080/webapp/rest/A1E-16094/delete
100000 Datensätze mit VARCHAR + CLOB wieder gelöscht
Zeit: 30.284013s
daniel@McPherson:./jboss-eap-7.4 $


Подробнее здесь: https://stackoverflow.com/questions/790 ... -in-oracle
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Как правильно ограничить строку для VARCHAR2 (4000 БАЙТ) в Oracle?
    Anonymous » » в форуме JAVA
    0 Ответы
    18 Просмотры
    Последнее сообщение Anonymous
  • Как правильно ограничить строку для VARCHAR2 (4000 БАЙТ) в Oracle?
    Anonymous » » в форуме JAVA
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous
  • Как правильно ограничить строку для VARCHAR2 (4000 БАЙТ) в Oracle?
    Anonymous » » в форуме JAVA
    0 Ответы
    15 Просмотры
    Последнее сообщение Anonymous
  • Как правильно ограничить строку для VARCHAR2 (4000 БАЙТ) в Oracle?
    Anonymous » » в форуме JAVA
    0 Ответы
    11 Просмотры
    Последнее сообщение Anonymous
  • Как правильно ограничить строку для VARCHAR2 (4000 БАЙТ) в Oracle?
    Anonymous » » в форуме JAVA
    0 Ответы
    10 Просмотры
    Последнее сообщение Anonymous

Вернуться в «JAVA»