오라클 10g small Blob 또는 Clob이 인라인으로 저장되지 않습니까?
제가 읽은 문서에 따르면, CLOB 또는 BLOB의 기본 저장소는 인라인 스토리지로, 크기가 약 4k 미만이면 테이블에 보관됩니다.
그러나 Oracle(10.2.0.1.0)의 더미 테이블에서 이를 테스트하면 Oracle Monitor(Allround Automations)의 성능과 응답이 테이블에서 유지되고 있음을 알 수 있습니다.
여기 제 시험 시나리오가 있습니다...
create table clobtest ( x int primary key, y clob, z varchar(100) )
;
insert into clobtest
select object_id, object_name, object_name
from all_objects where rownum < 10001
;
select COLUMN_NAME, IN_ROW
from user_lobs
where table_name = 'CLOBTEST'
;
다음과 같이 표시됩니다. YYES(Oracle이 clob을 행에 저장함을 의미함)
select x, y from CLOBTEST where ROWNUM < 1001 -- 8.49 seconds
select x, z from CLOBTEST where ROWNUM < 1001 -- 0.298 seconds
따라서 이 경우 CLOB 값은 최대 길이가 30자이므로 항상 인라인이어야 합니다.Oracle Monitor를 실행하면 LOB가 표시됩니다.길이 뒤에 LOB가 표시됩니다.반환되는 각 행에 대해 ()를 읽습니다. 이는 클로브 값이 테이블과 함께 유지됨을 다시 시사합니다.
저도 이렇게 테이블을 만들어 보았습니다.
create table clobtest
( x int primary key, y clob, z varchar(100) )
LOB (y) STORE AS (ENABLE STORAGE IN ROW)
정확히 같은 결과가 나왔습니다
(설득, 격려) 강요할 수 있는 방법을 제안해 주실 분 계신가요?테이블에 clob 값을 인라인으로 저장하는 오라클?(varchar2 컬럼 z를 읽는 것과 비슷한 응답 시간을 얻기를 희망합니다)
업데이트: 이 SQL을 실행하면
select COLUMN_NAME, IN_ROW, l.SEGMENT_NAME, SEGMENT_TYPE, BYTES, BLOCKS, EXTENTS
from user_lobs l
JOIN USER_SEGMENTS s
on (l.Segment_Name = s. segment_name )
where table_name = 'CLOBTEST'
다음과 같은 결과를 얻을 수 있습니다.
Y YES SYS_LOB0000398621C00002$$ LOBSEGMENT 65536 8 1
Oracle LOB의 동작은 다음과 같습니다.
LOB는 다음과 같은 경우 인라인으로 저장됩니다.
(
The size is lower or equal than 3964
AND
ENABLE STORAGE IN ROW has been defined in the LOB storage clause
) OR (
The value is NULL
)
LOB는 다음과 같은 경우에 행 외로 저장됩니다.
(
The value is not NULL
) AND (
Its size is higher than 3964
OR
DISABLE STORAGE IN ROW has been defined in the LOB storage clause
)
성능에 영향을 미칠 수 있는 문제는 이뿐만이 아닙니다.
최종적으로 LOB가 인라인으로 저장되지 않는 경우 Oracle의 기본 동작은 LOB의 캐싱을 방지하는 것입니다(인라인 LOB만 버퍼 캐시에 행의 다른 필드와 함께 캐싱됨).인라인이 아닌 LOB도 캐시하도록 Oracle에 지시하려면 LOB를 정의할 때 CASH 옵션을 사용해야 합니다.
기본 동작은 ENABLE STORE IN Row이며 NOCACH는 작은 LOB는 인라인 처리되고 큰 LOB는 캐시되지 않습니다.
마지막으로 통신 프로토콜 수준에서의 성능 문제도 있습니다.일반적인 Oracle 클라이언트는 LOB당 2번의 라운드 트립을 추가로 수행하여 이를 가져옵니다. 하나는 LOB의 크기를 검색하고 그에 따라 메모리를 할당합니다. 하나는 데이터 자체를 가져오는 것입니다(LOB가 작으면).
결과를 검색하기 위해 배열 인터페이스를 사용하는 경우에도 이러한 추가 라운드 트립이 수행됩니다.1000개의 행을 검색하고 배열 크기가 충분히 큰 경우, 행을 검색하는 데 1번의 왕복 비용을 지불하고 LOB의 내용을 검색하는 데 2000번의 왕복 비용을 지불합니다.
LOB가 인라인으로 저장되느냐 안 되느냐에 따라 달라지지는 않습니다.그것들은 완전히 다른 문제들입니다.
프로토콜 수준에서 최적화하기 위해 Oracle은 한 번의 왕복(OCILobArrayRead)으로 여러 LOB를 가져올 수 있는 새로운 OCI 동사를 제공했습니다.JDBC와 비슷한 것이 있는지 모르겠습니다.
또 다른 옵션은 클라이언트 측에서 LOB를 큰 RAW/VARCHAR2인 것처럼 바인딩하는 것입니다.이는 최대 크기의 LOB를 정의할 수 있는 경우에만 작동합니다(바인드 시간에 최대 크기를 제공해야 하므로).LOB는 RAW 또는 VARCHAR2와 같이 처리되기 때문에 추가적인 장애가 발생하지 않습니다.우리는 LOB 집약적인 애플리케이션에서 이를 많이 사용합니다.
왕복 횟수가 최적화되면, 패킷 크기(SDU)는 상황에 더 잘 맞도록 넷 구성에서 크기를 조정할 수 있습니다(즉, 제한된 수의 큰 왕복 횟수)."SQL*Net more data to client" 및 "SQL*Net more data from client" 대기 이벤트를 줄이는 경향이 있습니다.
만약 당신이 "varchar2 열 z를 읽는 것과 비슷한 응답 시간을 얻기를 바란다"고 한다면, 당신은 대부분의 경우 실망할 것입니다.CLOB를 사용하는 경우 4,000바이트 이상을 저장해야 하는 것으로 알고 있습니다.그러면 더 많은 바이트를 읽어야 한다면 더 오랜 시간이 걸릴 것입니다.
그러나 예, CLOB를 사용하지만 (경우에 따라) 열의 처음 4,000바이트(또는 그 이하)에만 관심이 있는 경우 유사한 성능을 얻을 수 있습니다.DBMS_LOB와 같은 것을 사용하면 Oracle이 검색을 최적화할 수 있을 것으로 보입니다.테이블과 함께 Substrate와 Enable STORE IN Row CASH 절.예:
CREATE TABLE clobtest (x INT PRIMARY KEY, y CLOB)
LOB (y) STORE AS (ENABLE STORAGE IN ROW CACHE);
INSERT INTO clobtest VALUES (0, RPAD('a', 4000, 'a'));
UPDATE clobtest SET y = y || y || y;
INSERT INTO clobtest SELECT rownum, y FROM all_objects, clobtest WHERE rownum < 1000;
CREATE TABLE clobtest2 (x INT PRIMARY KEY, z VARCHAR2(4000));
INSERT INTO clobtest2 VALUES (0, RPAD('a', 4000, 'a'));
INSERT INTO clobtest2 SELECT rownum, z FROM all_objects, clobtest2 WHERE rownum < 1000;
COMMIT;
10.2.0.4 및 8K 블록에 대한 테스트에서 이 두 쿼리는 매우 유사한 성능을 제공합니다.
SELECT x, DBMS_LOB.SUBSTR(y, 4000) FROM clobtest;
SELECT x, z FROM clobtest2;
SQL*Plus의 샘플(물리적 IO를 제거하기 위해 쿼리를 여러 번 실행):
SQL> SET AUTOTRACE TRACEONLY STATISTICS
SQL> SET TIMING ON
SQL>
SQL> SELECT x, y FROM clobtest;
1000 rows selected.
Elapsed: 00:00:02.96
Statistics
------------------------------------------------------
0 recursive calls
0 db block gets
3008 consistent gets
0 physical reads
0 redo size
559241 bytes sent via SQL*Net to client
180350 bytes received via SQL*Net from client
2002 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1000 rows processed
SQL> SELECT x, DBMS_LOB.SUBSTR(y, 4000) FROM clobtest;
1000 rows selected.
Elapsed: 00:00:00.32
Statistics
------------------------------------------------------
0 recursive calls
0 db block gets
2082 consistent gets
0 physical reads
0 redo size
18993 bytes sent via SQL*Net to client
1076 bytes received via SQL*Net from client
68 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1000 rows processed
SQL> SELECT x, z FROM clobtest2;
1000 rows selected.
Elapsed: 00:00:00.18
Statistics
------------------------------------------------------
0 recursive calls
0 db block gets
1005 consistent gets
0 physical reads
0 redo size
18971 bytes sent via SQL*Net to client
1076 bytes received via SQL*Net from client
68 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
1000 rows processed
보다시피, 일관된 get은 상당히 높지만, SQL*Net 라운드 트립과 바이트는 마지막 두 쿼리에서 거의 동일하며, 이는 실행 시간에 큰 차이를 가져다 줍니다.
한 가지 주의 사항: 일관성 있는 결과 세트가 큰 경우 성능 문제가 될 수 있습니다. 모든 것을 버퍼 캐시에 보관할 수는 없고 물리적 읽기가 매우 비싸지기 때문입니다.
행운을 빕니다.
건배.
실제로 행 내에 저장됩니다.바카르 대신 LOB를 사용하는 단순한 오버헤드를 처리할 가능성이 높습니다.공짜는 없습니다.DB는 행을 어디서 찾아야 할지 미리 알지 못하기 때문에 LOB가 클 경우를 대비해 여전히 "지시자를 따라" 추가 작업을 수행할 수 있습니다.바카르로 살 수 있다면, 그래야 합니다.8,000자를 처리하기 위한 2개의 변수와 같은 오래된 해킹도 더 높은 성능으로 비즈니스 케이스를 해결할 수 있습니다.
롭스는 느리고 조회하기 어려운 등입니다.긍정적으로 말하면, 그들은 4G가 될 수 있습니다.
4,000바이트가 조금 넘는 무언가를 이 클롭에 밀어넣어 성능이 어떻게 생겼는지 확인해 보는 것이 흥미로울 것 같습니다.아마 거의 비슷한 속도일까요?이것은 그것이 당신의 속도를 늦추는 오버헤드라는 것을 말해줄 것입니다.
경고: PC에 대한 네트워크 트래픽으로 인해 이러한 테스트 속도가 느려집니다.
카운트 단위로 래핑하여 이를 최소화하면 작업이 서버로 분리됩니다.
count (* )에서 선택합니다 (clobtest에서 x,y를 선택합니다. 여기서 행 번호 <1001)
set autot trace로 비슷한 효과를 얻을 수 있지만 오버헤드 추적도 있을 것입니다.
CLOBs와 BLOBs에 관해서는 두 가지 방향이 있습니다.
LOB 값은 행의 나머지 부분과는 다른 데이터베이스 세그먼트에 저장될 수 있습니다.
행을 쿼리하면 결과 집합에 LOB가 아닌 필드만 포함되며 LOB 필드에 액세스하려면 클라이언트와 서버 간에 한 번 이상의 왕복이 추가로 필요합니다(행당!).
실행 시간을 측정하는 방법을 잘 모르며 Oracle Monitor를 사용해 본 적은 없지만 두 번째 방향의 영향을 주로 받을 수 있습니다.사용하는 클라이언트 소프트웨어에 따라 왕복을 줄일 수 있습니다.예를 들어 ODP를 사용할 때.NET, 매개 변수를 InitialLobFetchSize라고 합니다.
업데이트:
두 방향 중 어떤 방향이 관련되어 있는지 알려주는 하나는 1000개 행으로 LOB 쿼리를 두 번 실행할 수 있습니다.첫 번째 실행에서 두 번째 실행으로 시간이 크게 떨어지면 방향 1입니다.두 번째 실행에서는 캐슁이 효과를 발휘하며 별도의 데이터베이스 세그먼트에 액세스하는 것은 더 이상 큰 관련이 없습니다.시간이 거의 동일하게 유지되는 경우 두 번째 방향 즉, 클라이언트와 서버 간 왕복 이동으로 두 번의 실행 사이를 개선할 수 없습니다.
매우 간단한 쿼리에서 1,000행의 경우 8초 이상의 시간이 소요된다는 것은 데이터가 매우 분산되어 있고 디스크 시스템에 부하가 많이 걸리지 않는 한 1,000행의 경우 8초는 디스크 액세스로 설명할 수 없기 때문에 간접 2임을 나타냅니다.
다음은 Oracle 설명서에는 없는 주요 정보(추가 왕복 없이 LOB를 읽는 방법)입니다.
또 다른 옵션은 클라이언트 측에서 LOB를 큰 RAW/VARCHAR2인 것처럼 바인딩하는 것입니다.이는 최대 크기의 LOB를 정의할 수 있는 경우에만 작동합니다(바인드 시간에 최대 크기를 제공해야 하므로).LOB는 RAW 또는 VARCHAR2와 같이 처리되기 때문에 추가적인 장애가 발생하지 않습니다.우리는 LOB 집약적인 애플리케이션에서 이를 많이 사용합니다.
blob column 하나(14KB = > 수천 행)로 간단한 테이블(몇 GB)을 로드하는 데 문제가 있었고 오랫동안 조사하고 있었고, lob storage tuning(DB_BLOCK_SIZE for new tablespace, lob storage specification - CHUNK), sqlnet.ora settings, client prefetching 속성,그러나 이것(클라이언트 측에서 OCCI ResultSet->setBufferData로 BLOB를 LONG RAW로 처리)이 가장 중요했습니다(처음에는 로브 로케이터를 보내지 않고 로브 열을 즉시 전송하도록 오라클을 설득하고 로브 로케이터를 기준으로 각 로브를 개별적으로 로드합니다).
이제 초당 500Mb의 처리량(열이 3964B 미만)까지 확보할 수 있습니다.14KB 블롭은 여러 열로 분리되어 HDD에서 거의 순차적으로 읽기 위해 일렬로 저장됩니다.14KB 블롭 하나(열 하나)를 사용하면 순차적이 아닌 읽기(iostat: 낮은 양의 병합 읽기 요청)로 인해 최대 150Mbit/s를 얻을 수 있습니다.
참고: 로브 프리페치 크기/길이 설정도 잊지 마십시오.
err = OCIAttrSet(세션, (ub4) OCI_HTYPE_SESSION, (세션 *) &default_desprefetch_size, 0, (ub4) OCI_ATTR_DEFULT_LOBPREFETCH_SIZE, errhp);
그러나 ODBC 커넥터로 동일한 가져오기 처리량을 달성하는 방법을 모르겠습니다.저는 성공하지 못하고 시도하고 있었습니다.
언급URL : https://stackoverflow.com/questions/7361729/oracle-10g-small-blob-or-clob-not-being-stored-inline
'sourcecode' 카테고리의 다른 글
ajax post 후 document.ready 실행 (0) | 2023.09.10 |
---|---|
How to see pending AJAX requests with Chrome (0) | 2023.09.10 |
jquery 중첩 ajax 호출 서식 지정 (0) | 2023.09.10 |
jQuery에서 "드래깅"을 감지할 수 있습니까? (0) | 2023.09.10 |
알 수 없는 콜백 매개 변수 수가 있는 Axios spread() (0) | 2023.09.10 |