1. 背景
Oracle の 10 億レベルのログ テーブルがオンラインに存在するため、インデックス クエリの遅延現象が発生しません。そのため、インデックス作成テスト用に 10 億レベルのテーブルと数千万レベルのテーブルをローカルに作成し、インデックス作成の前後のクエリ時間を観察します。 DML の挿入、更新、削除操作には時間がかかります
2、操作
- 10億レベルのデータテーブルと数千万レベルのデータテーブルを作成し、主キーとしてidを設定します
- 数千万のテーブル作成
CREATE TABLE TEST_LOG_DETAIL AS
SELECT
ROWNUM AS ID,
SYSDATE + ROWNUM / 24 / 3600 AS INSERT_TIME,
TRUNC(DBMS_RANDOM.VALUE(0, 100)) AS MONEY,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS USERFROM,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS PRODUCT,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS TAG,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS PAY_CODE,
DBMS_RANDOM.STRING('x',
8) USERNAME,
DBMS_RANDOM.STRING('x',
16) ORDER_ID,
DBMS_RANDOM.STRING('x',
8) ADD_FROM
FROM xmltable('1 to 15000000');
- 10億テーブルの作成
CREATE TABLE TEST1_LOG_DETAIL AS
SELECT
ROWNUM AS ID,
SYSDATE + ROWNUM / 24 / 3600 AS INSERT_TIME,
TRUNC(DBMS_RANDOM.VALUE(0, 100)) AS MONEY,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS USERFROM,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS PRODUCT,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS TAG,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS PAY_CODE,
DBMS_RANDOM.STRING('x',
8) USERNAME,
DBMS_RANDOM.STRING('x',
16) ORDER_ID,
DBMS_RANDOM.STRING('x',
8) ADD_FROM
FROM xmltable('1 to 150000000');
- 主キーを増やす
ALTER TABLE TEST_LOG_DETAIL
ADD CONSTRAINT TEST_LOG_DETAIL_PK PRIMARY KEY (ID)
ENABLE;
- DML をテストする前の準備作業、主キーの自動インクリメントの設定、ID 主キーの挿入失敗の回避
- 主キーの自動インクリメント機能を増やす(IDの末尾から自動インクリメントを開始するように自動インクリメント番号を設定)
CREATE SEQUENCE TEST_ID_SEQ
INCREMENT BY 1
START WITH 15000001
MAXVALUE 999999999
NOCYCLE
NOCACHE;
- 主キーの自動インクリメントトリガーを作成します (さまざまなテーブルに従って変更)
CREATE OR REPLACE TRIGGER TEST_ID_SEQ_TRG
BEFORE INSERT ON "TEST_LOG_DETAIL"
FOR EACH ROW
WHEN (NEW."ID" IS NULL)
BEGIN
SELECT TEST_ID_SEQ.NEXTVAL
INTO :NEW."ID"
FROM DUAL;
END;
- ランダムな 3000 個のデータを挿入します
INSERT
INTO
TEST_LOG_DETAIL (id,
INSERT_TIME,
MONEY,
USERFROM,
PRODUCT,
TAG,
PAY_CODE,
USERNAME,
ORDER_ID,
ADD_FROM)
SELECT
NULL,
SYSDATE + ROWNUM / 24 / 3600 AS INSERT_TIME,
TRUNC(DBMS_RANDOM.VALUE(0, 100)) AS MONEY,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS USERFROM,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS PRODUCT,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS TAG,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS PAY_CODE,
'TESTADMIN' USERNAME,
DBMS_RANDOM.STRING('x',
16) ORDER_ID,
DBMS_RANDOM.STRING('x',
8) ADD_FROM
FROM
DUAL
CONNECT BY
LEVEL <= 3000
- 3000件のデータを更新
UPDATE TEST_LOG_DETAIL SET MONEY = 1001 WHERE USERNAME ='TESTADMIN'
- 3000件のデータを削除
DELETE TEST_LOG_DETAIL WHERE USERNAME ='TESTADMIN'
- DQLクエリ操作
SELECT
USERNAME,
MONEY,
TO_CHAR(insert_time, 'yyyy-MM-dd HH24:mi:ss') AS insert_time,
ADD_FROM
FROM
TEST_LOG_DETAIL
WHERE
USERNAME = 'QUWO12TO'
AND userfrom = 0
AND insert_time >= TO_DATE('2022-12-21', 'YYYY-MM-DD')
AND insert_time <= TO_DATE('2023-01-03', 'YYYY-MM-DD')+ 1
ORDER BY
insert_time DESC
- ユーザー名フィールドによりインデックスが作成され、作成中に DML 操作を実行できません。
create index idx_TEST_USERNAME on TEST_LOG_DETAIL(USERNAME);
- 上記の DQL DML 操作を再度テストして、時間がかかることを確認します。
-
クエリとインデックス作成にかかる時間が大幅に削減されます。
-
インデックスフィールドのユーザー名の内容が固定されている場合は挿入に時間がかかり、固定されていない場合は挿入に時間がかかります。
-
インデックスの更新と実行にかかる時間が大幅に短縮され、インデックスを実行しない時間もわずかに短縮されます。
-
インデックスの削除と実行にかかる時間が大幅に短縮され、インデックスを実行しない時間もわずかに短縮されます。
- ユーザー名インデックスを削除する
DROP index idx_TEST_USERNAME;
- insert_time フィールドにインデックスを追加する
create index idx_TEST_INSERT_TIME ON TEST_LOG_DETAIL(INSERT_TIME);
- 上記の DQL DML 操作を再度テストして、時間がかかることを確認します。
- 3000個のデータを挿入し、挿入時間の変更と固定時間の消費を大幅に削減
INSERT
INTO
TEST_LOG_DETAIL (id,
INSERT_TIME,
MONEY,
USERFROM,
PRODUCT,
TAG,
PAY_CODE,
USERNAME,
ORDER_ID,
ADD_FROM)
SELECT
NULL,
TO_DATE('2023-01-03 16:20:00','yyyy-mm-dd hh24:mi:ss') AS INSERT_TIME,
TRUNC(DBMS_RANDOM.VALUE(0, 100)) AS MONEY,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS USERFROM,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS PRODUCT,
TRUNC(1004) AS TAG,
TRUNC(DBMS_RANDOM.VALUE(0, 9)) AS PAY_CODE,
DBMS_RANDOM.STRING('x',
8) USERNAME,
DBMS_RANDOM.STRING('x',
16) ORDER_ID,
DBMS_RANDOM.STRING('x',
8) ADD_FROM
FROM
DUAL
CONNECT BY
LEVEL <= 3000
-
クエリとインデックス作成にかかる時間が大幅に削減されます。
-
インデックスの更新と実行にかかる時間が大幅に短縮され、インデックスを実行しない時間もわずかに短縮されます。
-
インデックスの削除と実行にかかる時間は大幅に短縮され、インデックスを実行しない場合の時間は増加します。
3. 結論
データベースデータ | インデックスなし | ユーザー名のインデックス | 挿入時間インデックス |
---|---|---|---|
お問い合わせ | 9.458秒 | 110ミリ秒 | 77ミリ秒 |
3000 項目を挿入 | 523ミリ秒 | 479ミリ秒 | 402ミリ秒 |
3000アイテムを更新 | 9.548秒 | 12ミリ秒 | 5ミリ秒 |
3000 件のアイテムを削除 | 9.542秒 | 35ミリ秒 | 75ミリ秒 |
インデックスを追加した後、SQL ステートメントでインデックスを使用すると、DQL および DML 操作の時間が大幅に削減されますが、インデックスを使用しない場合は、DML 操作の時間が増加する可能性があります。大規模なログ テーブルでのクエリ操作が頻繁で遅く、耐えられない場合は、よく使用されるフィールドにインデックスを追加できますが、インデックスを追加しすぎないようにしてください。ほとんどのシナリオは時間範囲に合わせて最適化されています。時間フィールドにインデックスをロードします。同時に、インデックスの作成時にテーブルは DML 操作を実行できないことに注意してください。