大規模な Oracle ログ テーブルのクエリは遅く、DML 操作のさまざまなフィールドにインデックスを追加した場合の影響をテストするために、ペタバイト単位のデータがローカルでランダムに生成されます。

1. 背景

Oracle の 10 億レベルのログ テーブルがオンラインに存在するため、インデックス クエリの遅延現象が発生しません。そのため、インデックス作成テスト用に 10 億レベルのテーブルと数千万レベルのテーブルをローカルに作成し、インデックス作成の前後のクエリ時間を観察します。 DML の挿入、更新、削除操作には時間がかかります

2、操作

  1. 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;

ここに画像の説明を挿入

  1. 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;

ここに画像の説明を挿入

  1. ランダムな 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

ここに画像の説明を挿入

  1. 3000件のデータを更新
UPDATE TEST_LOG_DETAIL SET MONEY  = 1001 WHERE USERNAME ='TESTADMIN'

ここに画像の説明を挿入

  1. 3000件のデータを削除
DELETE  TEST_LOG_DETAIL  WHERE  USERNAME ='TESTADMIN'

ここに画像の説明を挿入

  1. 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

ここに画像の説明を挿入

  1. ユーザー名フィールドによりインデックスが作成され、作成中に DML 操作を実行できません。
create index idx_TEST_USERNAME on TEST_LOG_DETAIL(USERNAME);

ここに画像の説明を挿入

  1. 上記の DQL DML 操作を再度テストして、時間がかかることを確認します。
  • クエリとインデックス作成にかかる時間が大幅に削減されます。
    ここに画像の説明を挿入

  • インデックスフィールドのユーザー名の内容が固定されている場合は挿入に時間がかかり、固定されていない場合は挿入に時間がかかります。
    ここに画像の説明を挿入
    ここに画像の説明を挿入

  • インデックスの更新と実行にかかる時間が大幅に短縮され、インデックスを実行しない時間もわずかに短縮されます。ここに画像の説明を挿入ここに画像の説明を挿入

  • インデックスの削除と実行にかかる時間が大幅に短縮され、インデックスを実行しない時間もわずかに短縮されます。
    ここに画像の説明を挿入
    ここに画像の説明を挿入

  1. ユーザー名インデックスを削除する
DROP index idx_TEST_USERNAME;

ここに画像の説明を挿入

  1. insert_time フィールドにインデックスを追加する
create index idx_TEST_INSERT_TIME ON TEST_LOG_DETAIL(INSERT_TIME);

ここに画像の説明を挿入

  1. 上記の 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 操作を実行できないことに注意してください。

おすすめ

転載: blog.csdn.net/weixin_43288999/article/details/128529891
おすすめ