Oracle Database 23.7の開発者向け新機能 (2025/06/30)
Oracle Database 23.7の開発者向け新機能 (2025/06/30)
https://blogs.oracle.com/developers/whats-new-for-developers-in-oracle-database-23-7
投稿者:Gerald Venzl | Vice President, Developer & AI Initiatives
Oracle Database 23.6 の新機能の詳細については、 https ://blogs.oracle.com/developers/post/whats-new-for-developers-in-oracle-database-23-6 を参照してください。
TIME_BUCKET関数
trunc関数を使えば、行を日、時間、分単位でグループ化できます。しかし、行をN単位の時間スライス(例えば5分、2時間、3日)に分割するには、各グループの開始時刻と終了時刻を求める数式を記述する必要がありました。
このtime_bucket関数はこのロジックを大幅に簡素化します。最大5つのパラメータを使用して、指定された値が属する区間の開始時刻と終了時刻を特定できます。
- 日時 – バケットの値
- Stride– インターンバルとしての各グループのサイズ
- 原点 – 開始時刻と終了時刻を計算するための基準日
- start_or_end– 各バケットの開始または終了を返すかどうか(オプション。デフォルトは開始)
- timebucket_optional_clause– 戻り値が無効な日付の場合、または起点が月の最終日で、ストライドに月または年(あるいはその両方)のみが含まれる場合(オプション、デフォルトはオーバーフロー・ラウンド)の関数の動作を制御します
次の例は、5分、15分および90分バケット内の特定の値をバケット化するtime_bucketの使用を示しています。
ALTER SESSION SET NLS_DATE_FORMAT = ‘ HH24:MI ‘;
WITH times AS (
SELECT DATE ‘2025-01-21’ + ( LEVEL / 240 ) dt CONNECT BY LEVEL <= 4
)
SELECT dt, — value, bucket size, origin date, bucket start/end
TIME_BUCKET ( dt, INTERVAL ‘5’ MINUTE, TRUNC ( dt ) ) five,
TIME_BUCKET ( dt, INTERVAL ’15’ MINUTE, TRUNC ( dt ), START ) fifteen,
TIME_BUCKET ( dt, INTERVAL ’90’ MINUTE, TRUNC ( dt ), END ) ninety
FROM times ORDER BY dt;
DT FIVE FIFTEEN NINETY
__________ __________ __________ __________
00:06 00:05 00:00 01:30
00:12 00:10 00:00 01:30
00:18 00:15 00:15 01:30
00:24 00:20 00:15 01:30
すべての値が6分から24分の間であるため、すべての値が同じ90分バケット(endバケットの を返す)に収まっていることがわかります。ただし、最初の2行のみが0分バケットに収まり、残りの2行は15分バケット(startバケットの を返す)に収まります。また、どの値も同じ5分バケット(startバケットのデフォルト値を返す)に収まりません。
マテリアライズド列
11gで追加された仮想列により、開発者は以前から計算値を持つ列を定義できるようになりました。これらの列は、選択されるたびに計算を実行します。しかし、複雑な計算の場合、値を取得するたびに再計算する必要があるため、値が頻繁にクエリされる場合には、大幅なオーバーヘッドが発生し、応答時間が遅延する可能性があります。したがって、書き込みが少なく読み取りが多い値の場合は、データの挿入または変更時に計算結果を保存する方が効果的です。
23.7 のマテリアライズド列を使用すると、書き込み時に結果を格納する計算列を定義できます。これにより、処理が SELECT ステートメントから INSERT ステートメントおよび UPDATE ステートメントに移行され、書き込みは少なく読み取りは頻繁に行われるシナリオに最適ですが、書き込みは多く読み取りは少なく行われるシナリオでは逆のトレードオフがあります。
いずれかの列タイプの利点を示すために、複雑な計算をシミュレートするために0.1s待機がある関数incについて検討します。表my_tableには、ファンクションをコールする仮想列(value2)とマテリアライズド列(value3)の両方があります。
データベースがマテリアライズド列に結果を格納するため、10行の挿入には約1秒(10 * 0.1s待機時間in function inc)かかります。マテリアライズド列の問合せは10分の1秒未満です。ファンクションの待機が原因で、仮想列の問合せには少なくとも1秒かかります。
CREATE OR REPLACE FUNCTION inc (
v int,
i int
)
RETURN INT DETERMINISTIC AS
BEGIN
dbms_session.sleep ( 0.1 ); — wait 1/10th second
RETURN v + i;
END;
/
CREATE TABLE my_table (
value1 int,
value2 int
AS ( inc (value1, 1) ) VIRTUAL, — calc on read
value3 int
AS ( inc (value1, 2 )) MATERIALIZED — calc on write
);
set timing on
— The materialized column is written on write; runtime ~1s
INSERT INTO my_table ( value1 )
SELECT LEVEL
CONNECT BY LEVEL <= 10;
10 rows inserted.
Elapsed: 00:00:01.036
— Virtual col calls function at runtime; runtime ~1s
SELECT SUM ( value2 ) FROM my_table;
SUM(VALUE2)
______________
65
Elapsed: 00:00:01.053
— Materialized col stores function result on insert
— query runtime < 0.1s
SELECT SUM ( value3 ) FROM my_table;
SUM(VALUE3)
______________
75
Elapsed: 00:00:00.007
DBMS_DEVELOPER.GET_METADATA()
dbms_metadataパッケージは、長い間、DDL文またはXMLドキュメントとしてデータベース・オブジェクトの定義を取得する方法でした。これらの形式は、JSONをデータ交換形式として使用する多くのアプリケーションには実用的ではありません。dbms_developerパッケージは、表、ビューおよび索引のJSON表現を取得するためのAPIを提供します。この形式を指定する以外に、dbms_developerへのコールは、dbms_metadataコールよりもはるかに高速です。
CREATE TABLE my_table (
column1 INT NOT NULL PRIMARY KEY ANNOTATIONS (pk, nn, datatype ‘numeric’),
column2 DATE ANNOTATIONS (datatype ‘datetime’)
) ANNOTATIONS (note ‘example table’);
set timing on
SELECT JSON_SERIALIZE(
DBMS_DEVELOPER.GET_METADATA(‘MY_TABLE’)
PRETTY) table_info;
TABLE_INFO
_________________________________________________________
{
“objectType” : “TABLE”,
“objectInfo” :
{
“name” : “MY_TABLE”,
“schema” : “GERALD”,
“columns” :
[
{
“name” : “COLUMN1”,
“notNull” : true,
“dataType” :
{
“type” : “NUMBER”,
“precision” : 38
},
“isPk” : true,
“isUk” : true,
“isFk” : false,
“annotations” :
[
{
“name” : “PK”,
“value” : “”
},
{
“name” : “NN”,
“value” : “”
},
{
“name” : “DATATYPE”,
“value” : “numeric”
}
]
},
{
“name” : “COLUMN2”,
“notNull” : false,
“dataType” :
{
“type” : “DATE”
},
“isPk” : false,
“isUk” : false,
“isFk” : false,
“annotations” :
[
{
“name” : “DATATYPE”,
“value” : “datetime”
}
]
}
],
“hasBeenAnalyzed” : false,
“indexes” :
[
{
“name” : “SYS_C008825”,
“indexType” : “NORMAL”,
“uniqueness” : “UNIQUE”,
“status” : “VALID”,
“hasBeenAnalyzed” : false,
“columns” :
[
{
“name” : “COLUMN1”
}
]
}
],
“constraints” :
[
{
“name” : “SYS_C008824”,
“constraintType” : “CHECK – NOT NULL”,
“searchCondition” : “\”COLUMN1\” IS NOT NULL”,
“columns” :
[
{
“name” : “COLUMN1”
}
],
“status” : “ENABLE”,
“deferrable” : false,
“validated” : “VALIDATED”,
“sysGeneratedName” : true
},
{
“name” : “SYS_C008825”,
“constraintType” : “PRIMARY KEY”,
“columns” :
[
{
“name” : “COLUMN1”
}
],
“status” : “ENABLE”,
“deferrable” : false,
“validated” : “VALIDATED”,
“sysGeneratedName” : true
}
],
“annotations” :
[
{
“name” : “NOTE”,
“value” : “example table”
}
]
},
“etag” : “4F35940648C7CEC8DDA21C0580D767AF”
}
Elapsed: 00:00:00.080
SELECT DBMS_METADATA.GET_DDL(‘TABLE’, ‘MY_TABLE’);
DBMS_METADATA.GET_DDL(‘TABLE’,’MY_TABLE’)
_____________________________________________________________________________________________
CREATE TABLE “GERALD”.”MY_TABLE”
( “COLUMN1” NUMBER(*,0) NOT NULL ENABLE ANNOTATIONS(“DATATYPE” ‘numeric’, “NN”, “PK”),
“COLUMN2” DATE ANNOTATIONS(“DATATYPE” ‘datetime’),
PRIMARY KEY (“COLUMN1”)
USING INDEX PCTFREE 10 INITRANS 2 MAXTRANS 255
TABLESPACE “USERS” ENABLE
) SEGMENT CREATION DEFERRED
PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255
NOCOMPRESS LOGGING
TABLESPACE “USERS”
ANNOTATIONS(“NOTE” ‘example table’)
Elapsed: 00:00:03.01
dbms_developer.get_metadata関数は、コール元のシグネチャも簡略化します。dbms_metadata.get_xxx関数では常に最初の入力パラメータとしてオブジェクト型が必要ですが、dbms_developer.get_metadataでは名前解決を介して型を遅延できます。ただし、同じスキーマ内で同じ名前を持つオブジェクト・タイプもあります。そのような例として、索引と表があります。その場合、dbms_developer.get_metadataはデフォルトで表に設定されます。
CREATE INDEX my_table ON my_table (column2);
SELECT JSON_SERIALIZE(
DBMS_DEVELOPER.GET_METADATA(‘MY_TABLE’) — information for the table is being retrieved
PRETTY) info;
INFO
_________________________________________________________
{
“objectType” : “TABLE”,
“objectInfo” :
{
“name” : “MY_TABLE”,
“schema” : “GERALD”,
“columns” :
[
{
“name” : “COLUMN1”,
“notNull” : true,
“dataType” :
{
“type” : “NUMBER”,
“precision” : 38
},
“isPk” : true,
“isUk” : true,
“isFk” : false,
“annotations” :
[
{
“name” : “DATATYPE”,
“value” : “numeric”
},
{
“name” : “NN”,
“value” : “”
},
{
“name” : “PK”,
“value” : “”
}
]
},
{
“name” : “COLUMN2”,
“notNull” : false,
“dataType” :
{
“type” : “DATE”
},
“isPk” : false,
“isUk” : false,
“isFk” : false,
“annotations” :
[
{
“name” : “DATATYPE”,
“value” : “datetime”
}
]
}
],
“hasBeenAnalyzed” : false,
“indexes” :
[
{
“name” : “SYS_C008825”,
“indexType” : “NORMAL”,
“uniqueness” : “UNIQUE”,
“status” : “VALID”,
“hasBeenAnalyzed” : false,
“columns” :
[
{
“name” : “COLUMN1”
}
]
},
{
“name” : “MY_TABLE”,
“indexType” : “NORMAL”,
“uniqueness” : “NONUNIQUE”,
“status” : “VALID”,
“lastAnalyzed” : “2025-05-06T22:53:27”,
“numRows” : 0,
“sampleSize” : 0,
“columns” :
[
{
“name” : “COLUMN2”
}
]
}
],
“constraints” :
[
{
“name” : “SYS_C008824”,
“constraintType” : “CHECK – NOT NULL”,
“searchCondition” : “\”COLUMN1\” IS NOT NULL”,
“columns” :
[
{
“name” : “COLUMN1”
}
],
“status” : “ENABLE”,
“deferrable” : false,
“validated” : “VALIDATED”,
“sysGeneratedName” : true
},
{
“name” : “SYS_C008825”,
“constraintType” : “PRIMARY KEY”,
“columns” :
[
{
“name” : “COLUMN1”
}
],
“status” : “ENABLE”,
“deferrable” : false,
“validated” : “VALIDATED”,
“sysGeneratedName” : true
}
],
“annotations” :
[
{
“name” : “NOTE”,
“value” : “example table”
}
]
},
“etag” : “C16F4A72C0DAA3FE25792BCF0F8F22BE”
}
インデックスに関する情報を取得するには、object_type => 'INDEX'を指定します。
SELECT JSON_SERIALIZE(
DBMS_DEVELOPER.GET_METADATA(‘MY_TABLE’, object_type => ‘INDEX’) — information for the index is retrieved
PRETTY) index_info;
INDEX_INFO
________________________________________________
{
“objectType” : “INDEX”,
“objectInfo” :
{
“name” : “MY_TABLE”,
“indexType” : “NORMAL”,
“Owner” : “GERALD”,
“tableName” : “MY_TABLE”,
“status” : “VALID”,
“columns” :
[
{
“name” : “COLUMN2”,
“notNull” : false,
“dataType” :
{
“type” : “DATE”
},
“isPk” : false,
“isUk” : false,
“isFk” : false,
“annotations” :
[
{
“name” : “DATATYPE”,
“value” : “datetime”
}
]
}
],
“uniqueness” : “NONUNIQUE”,
“lastAnalyzed” : “2025-05-06T22:53:27”,
“numRows” : 0,
“sampleSize” : 0
},
“etag” : “F7E1D5694ACE1D9B265861453A597FDB”
}
最後に、dbms_developer.get_metadataには、必要なメタデータの情報レベルとタグの2つの追加パラメータがあります。
レベルは、BASIC、TYPICAL (デフォルト)およびALLに設定できます。各値は、追加レベルの情報を提供します。レベル値名は、STATISTICS_LEVELパラメータなど、既存の他の機能と一致します。
etagパラメータを使用して、既知のメタデータ・ドキュメントのetagを指定できます。指定されたetagが現在のメタデータ・ドキュメントのetagと一致する場合、この関数は空のドキュメントを返します。すでに認識されているメタデータ・ドキュメントと新しく生成されたメタデータ・ドキュメントとの間に違いはありません。つまり、オブジェクトは変更されていません。データベース内のドキュメントのタグが指定されたタグと一致しない場合、新しいドキュメントが(新しい埋込みetagとともに)返されます。これは、実際に変更されたオブジェクトに関する情報のみを収集し、残りのオブジェクトは無視するきちんとした方法です。もちろん、アプリケーションはetagの値に注意を払い、それらに固執する必要があります。ノート: 結果のJSONドキュメントに対してetagが計算されるため、levelパラメータを変更すると新しいetagも生成されます。つまり、異なるレベルのタグは一致しません。
SELECT JSON_SERIALIZE(
DBMS_DEVELOPER.GET_METADATA(‘MY_TABLE’, level => ‘BASIC’)
PRETTY) table_info;
TABLE_INFO
________________________________________________
{
“objectType” : “TABLE”,
“objectInfo” :
{
“name” : “MY_TABLE”,
“schema” : “GERALD”,
“columns” :
[
{
“name” : “COLUMN1”,
“notNull” : true,
“dataType” :
{
“type” : “NUMBER”,
“precision” : 38
}
},
{
“name” : “COLUMN2”,
“notNull” : false,
“dataType” :
{
“type” : “DATE”
}
}
]
},
“etag” : “B644E9475669B3BDE09337481D39E0FB”
}
SELECT JSON_SERIALIZE(
dbms_developer.get_metadata(
‘MY_TABLE’, — object name
USER, — schema, default USER
‘TABLE’, — object type, optional
‘BASIC’, — information level BASIC|TYPICAL|ALL
‘B644E9475669B3BDE09337481D39E0FB’ — etag for the expected metadata as above
)
PRETTY) table_info;
TABLE_INFO
_____________
{
}
詳細については、https ://docs.oracle.com/en/database/oracle/oracle-database/23/arpls/dbms_developer1.html を参照してください。
JavaScript から PL/SQL コードユニットを呼び出すための外部関数インターフェース
Multilingual Engine(MLE)を使用すると、JavaScriptモジュールをOracle Databaseにロードし、SQLまたはPL/SQLでアクセスできるようになります。23.7以降では、これらのモジュールでネイティブJavaScriptを使用してPL/SQLパッケージを呼び出すことができます。
たとえば、JavaScript を使用して組み込みのDBMS_RANDOMPL/SQL パッケージを呼び出し、1 から 100 までの乱数を生成します。
CREATE OR REPLACE FUNCTION get_random_number(
p_lower_bound NUMBER,
p_upper_bound NUMBER
) RETURN NUMBER
AS MLE LANGUAGE JAVASCRIPT {{
const { resolvePackage } = await import (‘mle-js-plsql-ffi’);
const dbmsRandom = resolvePackage(‘dbms_random’);
return dbmsRandom.value(P_LOWER_BOUND, P_UPPER_BOUND);
}};
/
SELECT get_random_number (1, 100);
GET_RANDOM_NUMBER(1,100)
___________________________
96.683520107954
Smallfile 表領域の縮小
表を削除してごみ箱から取り除くと、Oracle Databaseは表領域内でその表が占めていた領域を解放します。理論上は、他のオブジェクトがこの領域を使用できるようになります。しかし、解放された領域が小さすぎて他のオブジェクトが使用できない場合があります。多くの表を削除すると、データベースが再利用できない小さな領域が多数残る可能性があります。これはフラグメンテーションと呼ばれ、必要以上にディスク領域が使用される原因となります。
BIGFILEOracle Database 23ai以降では、を使用して表領域(11g以降の推奨デフォルト)の失われた領域を再利用できるようになりましたdbms_space.shrink_tablespace。23.7以降では、パッケージSMALLFILEを使用して表領域内のこの領域も再dbms_space利用できるようになりました。再利用される領域の大きさを見積もるには、まず分析モードで実行してください。
例えば、表領域からどれだけのスペースを再利用できるかを確認しますSMALL_FILE。レポートによると、表領域のサイズは現在0.78GBですが、縮小することで0.2GBまで削減できます。
set serveroutput on;
execute dbms_space.shrink_tablespace ( ‘SMALL_FILE’, shrink_mode => DBMS_SPACE.TS_SHRINK_MODE_ANALYZE );
——————-ANALYZE RESULT——————-
Total Movable Objects: 29
Total Movable Size(GB): .11
Original Datafile Size(GB): .78
Suggested Target Size(GB): .2
Process Time: +00 00:00:13.453359
この後に縮小を実行すると、表領域内のオブジェクトが再編成され、0.19GB に縮小されます。つまり、0.59GB が節約されます。
execute dbms_space.shrink_tablespace ( ‘SMALL_FILE’ );
——————-SHRINK RESULT——————-
Total Moved Objects: 29
Total Moved Size(GB): .11
Original Datafile Size(GB): .78
New Datafile Size(GB): .19
Process Time: +00 00:02:54.715593
このブログ投稿はChris Saxonと共同執筆されました。
コメント
コメントを投稿