Размер lob oracle как посмотреть
Перейти к содержимому

Размер lob oracle как посмотреть

  • автор:

ORA-20000

Понадобилось определить размер clob в байтах. В базе установлена многобайтовая кодировка AL32UTF8 . Функция length и dbms_lob.getlength возращают результат в символах, функция lengthb не применима для clob, если используется многобайтовая кодировка (функция возращает ошибку » ORA-22998: CLOB и NCLOB в многобайтовых кодовых таблицах не поддерживается «).

Для определения размера пришлось сначала конвертировать clob в blob, а потом уже определить размер blob в байтах.

 
function clob_to_blob(p_clob in clob
) return blob
is
v_blob blob := null;


v_in pls_integer := 1;
v_out pls_integer := 1;

v_lang pls_integer := dbms_lob.default_lang_ctx;
v_warning pls_integer := dbms_lob.no_warning;
begin
if (p_clob is not null) then
dbms_lob.createtemporary(v_blob, true, dbms_lob.session);

dbms_lob.convertToBlob( dest_lob => v_blob
,src_clob => p_clob
,amount => dbms_lob.getlength(p_clob)
,dest_offset => v_in
,src_offset => v_out
,blob_csid => dbms_lob.default_csid
,lang_context => v_lang
,warning => v_warning
);
end if;
return v_blob;
end clob_to_blob;

function get_clob_size_in_bytes(p_clob in clob
) return number
is
v_blob blob;
v_result number := null;
begin
v_blob := clob_to_blob(p_clob => p_clob);
if (v_blob is not null) then
v_result := dbms_lob.getlength(v_blob);

if (dbms_lob.istemporary(lob_loc => v_blob) = 1) then
dbms_lob.freetemporary(v_blob);
end if;
end if;
return v_result;
end get_clob_size_in_bytes;

Сравнение dbms_lob.getlength() и length() для BLOB Oracle

Для точного определения размера BLOB в байтах рекомендуется использовать метод DBMS_LOB.GETLENGTH :

Скопировать код

-- Для точного подсчёта байтов BLOB: SELECT DBMS_LOB.GETLENGTH(blob_column) FROM ваш_таблица;

Используйте DBMS_LOB.GETLENGTH для BLOB, а функцию LENGTH для CLOB.

Почему dbms_lob.getlength() для BLOB?

DBMS_LOB.GETLENGTH позволяет точно определить размер BLOB, не принимая во внимание особенности кодировок, и даст вам реальное количество байт. BLOB представляет собой бинарный объект.

Будьте внимательны при использовании length() для BLOB!

Использование функции LENGTH() для BLOB похоже на измерение роста в свечах – результат будет только приближенным. Функция LENGTH() подсчитывает символы, а не байты, и может неправильно обработать символы с двойной шириной.

Многобайтовые символы? Не страшно

При работе с многобайтовыми символами важно использовать DBMS_LOB.GETLENGTH , которая не даст сбоев. Оставьте LENGTH() для работы с CLOB, где количество символов важнее их объема в байтах.

Практический пример – размер изображения

DBMS_LOB.GETLENGTH позволит точно определить размеры файлов изображений в формате «.bmp», сохранённых BLOB. Это важно при извлечении изображений, оптимизации их хранения и передачи.

Визуализация

Представьте, что вы взвешиваете контейнер перед отправкой:

Метод Точность Скорость Область применения
dbms_lob.getLength() ��️‍♂️ (Точно) �� (Быстро) ⚓ Морская промышленность
length() �� (Прибл.) �� (Медленее) �� Курьерская доставка
  • dbms_lob.getLength() как морские весы с высокой точностью и скоростью.
  • length() подходит для неспешных обычных посылок.

Помните: «В BLOB каждый байт на счету, а в CLOB количество символов важнее их объема.» ��

Проблемы и способы их избежать

Не допускайте смущения от length()

Использование LENGTH() для размера BLOB может привести к проблемам с производительностью или ошибкам из-за неправильной обработки символов. Размер не всегда имеет значение!

Особенности многобайтовых символов

Некоторые кодировки, такие как ‘AL32UTF8’, включают многобайтовые символы, которые могут искажать размер BLOB. Однако DBMS_LOB.GETLENGTH предоставит вам точный объем в байтах.

Полезные советы

Вам известна ваша кодировка?

В любой кодировке, будь это ‘WE8ISO8859P1’ или ‘AL32UTF8’, важно точно считать байты. И тут ваш выбор – DBMS_LOB.GETLENGTH .

Это полезно при миграции данных

Если вам нужно перенести BLOB, опирайтесь на DBMS_LOB.GETLENGTH для гарантии целостности данных.

Полезные материалы

  1. DBMS_LOB — Официальная документация Oracle по модели LOB.
  2. Is there a coding convention for a «line rule» for Java – Stack Overflow — Диалог разработчиков о кодовых соглашениях, включая использование DBMS_LOB.getLength.
  3. LTRIM — Подробнее о функции LENGTH(), также известной как LTRIM.
  4. How to Update millions or records in a table – Ask TOM — Обсуждение обработки BLOB в Ask TOM, акцентирующее внимание на массовых обновлениях.

Пройдя по ссылкам, будьте готовы к тому, что они могут отвлечь вас от основной темы.

Большие двоичные объекты (LOB) Oracle

Поставщик данных платформа .NET Framework для Oracle включает OracleLob класс, который используется для работы с типами данных бизнес-аналитики Oracle.

OracleLob может быть одним из следующих OracleType типов данных:

Тип данных Description
Большой двоичный объект Тип данных BLOB Oracle, содержащий двоичные данные с максимальным размером 4 гигабайта. Это сопоставляется с массивом типа Byte.
Clob Тип данных Oracle CLOB , содержащий символьные данные на основе набора символов по умолчанию на сервере с максимальным размером 4 гигабайта. Это сопоставляется со строкой .
Nclob Тип данных Oracle NCLOB , содержащий символьные данные на основе национального набора символов на сервере с максимальным размером 4 гигабайта. Это сопоставляется со строкой .

OracleLob отличается от OracleBFile того, что данные хранятся на сервере вместо физического файла в операционной системе. Он также может быть объектом чтения и записи, в отличие от OracleBFile, который всегда доступен только для чтения.

Создание, получение и запись LOB

В следующем примере C# показано, как можно создавать бизнес-объекты в таблице Oracle, а затем извлекать и записывать их в виде объектов OracleLob . В примере демонстрируется использование OracleDataReader объекта и методов OracleLobRead and Write . В этом примере используются типы данных Oracle BLOB, CLOB и NCLOB .

using System; using System.IO; using System.Text; using System.Data; using System.Data.OracleClient; // LobExample public class LobExample < public static int Main(string[] args) < //Create a connection. OracleConnection conn = new OracleConnection( "Data Source=Oracle8i;Integrated Security=yes"); using(conn) < //Open a connection. conn.Open(); OracleCommand cmd = conn.CreateCommand(); //Create the table and schema. CreateTable(cmd); //Read example. ReadLobExample(cmd); //Write example WriteLobExample(cmd); >return 1; > // ReadLobExample public static void ReadLobExample(OracleCommand cmd) < int actual = 0; // Table Schema: // "CREATE TABLE tablewithlobs (a int, b BLOB, c CLOB, d NCLOB)"; // "INSERT INTO tablewithlobs values (1, 'AA', 'AAA', N'AAAA')"; // Select some data. cmd.CommandText = "SELECT * FROM tablewithlobs"; OracleDataReader reader = cmd.ExecuteReader(); using(reader) < //Obtain the first row of data. reader.Read(); //Obtain the LOBs (all 3 varieties). OracleLob blob = reader.GetOracleLob(1); OracleLob clob = reader.GetOracleLob(2); OracleLob nclob = reader.GetOracleLob(3); //Example - Reading binary data (in chunks). byte[] buffer = new byte[100]; while((actual = blob.Read(buffer, 0, buffer.Length)) >0) Console.WriteLine(blob.LobType + ".Read(" + buffer + ", " + buffer.Length + ") => " + actual); // Example - Reading CLOB/NCLOB data (in chunks). // Note: You can read character data as raw Unicode bytes // (using OracleLob.Read as in the above example). // However, because the OracleLob object inherits directly // from the .NET stream object, // all the existing classes that manipulate streams can // also be used. For example, the // .NET StreamReader makes it easier to convert the raw bytes // into actual characters. StreamReader streamreader = new StreamReader(clob, Encoding.Unicode); char[] cbuffer = new char[100]; while((actual = streamreader.Read(cbuffer, 0, cbuffer.Length)) >0) Console.WriteLine(clob.LobType + ".Read( " + new string(cbuffer, 0, actual) + ", " + cbuffer.Length + ") => " + actual); // Example - Reading data (all at once). // You could use StreamReader.ReadToEnd to obtain // all the string data, or simply // call OracleLob.Value to obtain a contiguous allocation // of all the data. Console.WriteLine(nclob.LobType + ".Value => " + nclob.Value); > > // WriteLobExample public static void WriteLobExample(OracleCommand cmd) < //Note: Updating LOB data requires a transaction. cmd.Transaction = cmd.Connection.BeginTransaction(); // Select some data. // Table Schema: // "CREATE TABLE tablewithlobs (a int, b BLOB, c CLOB, d NCLOB)"; // "INSERT INTO tablewithlobs values (1, 'AA', 'AAA', N'AAAA')"; cmd.CommandText = "SELECT * FROM tablewithlobs FOR UPDATE"; OracleDataReader reader = cmd.ExecuteReader(); using(reader) < // Obtain the first row of data. reader.Read(); // Obtain a LOB. OracleLob blob = reader.GetOracleLob(1/*0:based ordinal*/); // Perform any desired operations on the LOB // (read, position, and so on). // Example - Writing binary data (directly to the backend). // To write, you can use any of the stream classes, or write // raw binary data using // the OracleLob write method. Writing character vs. binary // is the same; // however note that character is always in terms of // Unicode byte counts // (for example, even number of bytes - 2 bytes for every // Unicode character). byte[] buffer = new byte[100]; buffer[0] = 0xCC; buffer[1] = 0xDD; blob.Write(buffer, 0, 2); blob.Position = 0; Console.WriteLine(blob.LobType + ".Write( " + buffer + ", 0, 2) =>" + blob.Value); // Example - Obtaining a temp LOB and copying data // into it from another LOB. OracleLob templob = CreateTempLob(cmd, blob.LobType); long actual = blob.CopyTo(templob); Console.WriteLine(blob.LobType + ".CopyTo( " + templob.Value + ") => " + actual); // Commit the transaction now that everything succeeded. // Note: On error, Transaction.Dispose is called // (from the using statement) // and will automatically roll back the pending transaction. cmd.Transaction.Commit(); > > // CreateTempLob public static OracleLob CreateTempLob( OracleCommand cmd, OracleType lobtype) < //Oracle server syntax to obtain a temporary LOB. cmd.CommandText = "DECLARE A " + lobtype + "; "+ "BEGIN "+ "DBMS_LOB.CREATETEMPORARY(A, FALSE); "+ ":LOC := A; "+ "END;"; //Bind the LOB as an output parameter. OracleParameter p = cmd.Parameters.Add("LOC", lobtype); p.Direction = ParameterDirection.Output; //Execute (to receive the output temporary LOB). cmd.ExecuteNonQuery(); //Return the temporary LOB. return (OracleLob)p.Value; >// CreateTable public static void CreateTable(OracleCommand cmd) < // Table Schema: // "CREATE TABLE tablewithlobs (a int, b BLOB, c CLOB, d NCLOB)"; // "INSERT INTO tablewithlobs VALUES (1, 'AA', 'AAA', N'AAAA')"; try < cmd.CommandText = "DROP TABLE tablewithlobs"; cmd.ExecuteNonQuery(); >catch(Exception) < >cmd.CommandText = "CREATE TABLE tablewithlobs (a int, b BLOB, c CLOB, d NCLOB)"; cmd.ExecuteNonQuery(); cmd.CommandText = "INSERT INTO tablewithlobs VALUES (1, 'AA', 'AAA', N'AAAA')"; cmd.ExecuteNonQuery(); > > 

Создание временного объекта LOB

В следующем примере на языке C# демонстрируется создание временного объекта LOB.

OracleConnection conn = new OracleConnection( "server=test8172; integrated security=yes;"); conn.Open(); OracleTransaction tx = conn.BeginTransaction(); OracleCommand cmd = conn.CreateCommand(); cmd.Transaction = tx; cmd.CommandText = "declare xx blob; begin dbms_lob.createtemporary( xx, false, 0); :tempblob := xx; end;"; cmd.Parameters.Add(new OracleParameter("tempblob", OracleType.Blob)).Direction = ParameterDirection.Output; cmd.ExecuteNonQuery(); OracleLob tempLob = (OracleLob)cmd.Parameters[0].Value; tempLob.BeginBatch(OracleLobOpenMode.ReadWrite); tempLob.Write(tempbuff,0,tempbuff.Length); tempLob.EndBatch(); cmd.Parameters.Clear(); cmd.CommandText = "myTable.myProc"; cmd.CommandType = CommandType.StoredProcedure; cmd.Parameters.Add(new OracleParameter( "ImportDoc", OracleType.Blob)).Value = tempLob; cmd.ExecuteNonQuery(); tx.Commit(); 

См. также

  • Oracle и ADO.NET
  • Общие сведения об ADO.NET

dbms_lob.getlength() vs. length() to find blob size in oracle

However, the answers to this question seem to favor using dbms_lob.getlength() . Is there any benefit to using dbms_lob.getlength() ? If it changes the answer, I know all of the BLOBs are .bmp images (never worked with BLOBs before).

5,092 14 14 gold badges 32 32 silver badges 53 53 bronze badges
asked Mar 3, 2010 at 16:44
user285498 user285498

1 Answer 1

length and dbms_lob.getlength return the number of characters when applied to a CLOB (Character LOB). When applied to a BLOB (Binary LOB), dbms_lob.getlength will return the number of bytes, which may differ from the number of characters in a multi-byte character set.

As the documentation doesn’t specify what happens when you apply length on a BLOB, I would advise against using it in that case. If you want the number of bytes in a BLOB, use dbms_lob.getlength .

answered Mar 3, 2010 at 16:56
Vincent Malgrat Vincent Malgrat
67.3k 9 9 gold badges 120 120 silver badges 174 174 bronze badges

Or if you know you are working with BLOBs and not CLOBs or NCLOBs use lengthb(BLOB) to get the number of bytes in the BLOB.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *