

# Aurora DSQL の非同期インデックス
<a name="working-with-create-index-async"></a>

`CREATE INDEX ASYNC` コマンドは、指定されたテーブルの 1 つ以上の列にインデックスを作成します。このコマンドは、他のトランザクションをブロックしない非同期 DDL オペレーションです。`CREATE INDEX ASYNC` を実行すると、Aurora DSQL はすぐに `job_id` を返します。

この非同期ジョブのステータスは、`sys.jobs` システムビューでモニタリングできます。インデックス作成ジョブが進行中の場合は、次のプロシージャとコマンドを使用できます。

**`sys.wait_for_job(job_id)'your_index_creation_job_id'`**  
指定されたジョブが完了または失敗するまでセッションをブロックします。成功または失敗を示すブール値を返します。

**`DROP INDEX`**  
進行中のインデックスビルドジョブをキャンセルします。  
Aurora DSQL が非同期インデックスの作成を完了すると、システムカタログが更新され、インデックスがアクティブであることが示されます。  
 この更新中に同じネームスペース内のオブジェクトにアクセスする同時トランザクションでは、同時実行エラーが発生する可能性があります。

Aurora DSQL が非同期インデックスタスクを完了すると、システムカタログが更新され、インデックスがアクティブであることが示されます。この時点で他のトランザクションが同じネームスペース内のオブジェクトを参照している場合、同時実行エラーが表示されることがあります。

## 構文
<a name="working-with-create-index-syntax"></a>

`CREATE INDEX ASYNC` は以下の構文を使用します。

```
CREATE [ UNIQUE ] INDEX ASYNC [ IF NOT EXISTS ] name ON table_name 
     ( { column_name } [ NULLS { FIRST | LAST } ] ) 
     [ INCLUDE ( column_name [, ...] ) ] 
     [ NULLS [ NOT ] DISTINCT ]
```

## パラメータ
<a name="working-with-create-index-parameters"></a>

**`UNIQUE`**  
Aurora DSQL がインデックスを作成する際、およびデータを追加するたびに、テーブル内の重複した値をチェックすることを示します。このパラメータを指定した場合、エントリが重複するオペレーションを挿入および更新すると、エラーが発生します。

**`IF NOT EXISTS`**  
同じ名前のインデックスが既に存在する場合、Aurora DSQL が例外をスローすべきではないことを示します。この場合、Aurora DSQL は新しいインデックスを作成しません。作成しようとしているインデックスは、存在するインデックスとは大きく異なる構造を持つ可能性があることに注意してください。このパラメータを指定する場合、インデックス名は必須です。

**`name`**  
インデックスの名前。このパラメータにスキーマの名前を含めることはできません。  
Aurora DSQL は、親テーブルと同じスキーマにインデックスを作成します。インデックスの名前は、スキーマ内のテーブルやインデックスなどの他のオブジェクトの名前とは異なる必要があります。  
名前を指定しない場合、Aurora DSQL は親テーブルとインデックス付き列の名前に基づいて名前を自動的に生成します。例えば、`CREATE INDEX ASYNC on table1 (col1, col2)` を実行すると、Aurora DSQL は自動的にインデックス `table1_col1_col2_idx` に名前を付けます。

**`NULLS FIRST | LAST`**  
null 列と null 列以外の列のソート順。`FIRST` は、Aurora DSQL が null 列以外の列の前に null 列をソートする必要があることを示します。`LAST` は、Aurora DSQL が null 列以外の列の後に null 列をソートする必要があることを示します。

**`INCLUDE`**  
非キー列としてインデックスに含める列のリスト。インデックススキャン検索条件にキー以外の列を使用することはできません。Aurora DSQL は、インデックスの一意性の観点から列を無視します。

**`NULLS DISTINCT | NULLS NOT DISTINCT`**  
Aurora DSQL が一意のインデックスで null 値を個別と見なすかどうかを指定します。デフォルトは `DISTINCT` です。つまり、一意のインデックスには列に複数の null 値を含めることができます。`NOT DISTINCT` は、インデックスが列に複数の null 値を含めることができないことを示します。

## 使用に関する注意事項
<a name="working-with-create-index-usage-notes"></a>

以下のガイドラインを検討します。
+ `CREATE INDEX ASYNC` コマンドはロックを導入しません。また、Aurora DSQL がインデックスの作成に使用するベーステーブルにも影響しません。
+ スキーマ移行オペレーション中は、`sys.wait_for_job(job_id)'your_index_creation_job_id'` のプロシージャが役立ちます。これにより、後続の DDL および DML オペレーションが新しく作成されたインデックスをターゲットにします。
+ Aurora DSQL は、新しい非同期タスクを実行するたびに、`sys.jobs` ビューをチェックし、30 分以上ステータスが `completed` または `failed` のタスクを削除します。したがって、`sys.jobs` では主に進行中のタスクが表示され、古いタスクに関する情報は含まれません。
+ Aurora DSQL が非同期インデックスの構築に失敗した場合、インデックスは `INVALID` のままになります。一意のインデックスの場合、インデックスを削除するまで、DML オペレーションは一意性の制約を受けます。無効なインデックスを削除して再作成することをお勧めします。

## インデックスの作成: 例
<a name="working-with-create-index-example"></a>

次の例は、スキーマ、テーブル、インデックスを作成する方法を示しています。

1. `test.departments` という名前のテーブルを作成します。

   ```
   CREATE SCHEMA test;
   
   CREATE TABLE test.departments (name varchar(255) primary key NOT null, 
        manager varchar(255), 
        size varchar(4));
   ```

1. テーブルに行を挿入します。

   ```
   INSERT INTO test.departments VALUES ('Human Resources', 'John Doe', '10')
   ```

1. 非同期インデックスを作成します。

   ```
   CREATE INDEX ASYNC test_index on test.departments(name, manager, size);
   ```

   `CREATE INDEX` コマンドは、次に示すようにジョブ ID を返します。

   ```
   job_id 
   -------------------------- 
   jh2gbtx4mzhgfkbimtgwn5j45y
   ```

   `job_id` は、Aurora DSQL がインデックスを作成するための新しいジョブを送信したことを示します。`sys.wait_for_job(job_id)'your_index_creation_job_id'` のプロシージャを使用して、ジョブが終了またはタイムアウトするまでセッションの他の作業をブロックできます。

## インデックス作成のステータスのクエリ: 例
<a name="dsql-index-status-example"></a>

次の例に示すように、`sys.jobs` システムビューをクエリしてインデックスの作成ステータスを確認します。

```
SELECT * FROM sys.jobs where job_id = 'wqhu6ewifze5xitg3umt24h5ua';
```

Aurora DSQL は、次のようなレスポンスを返します。

```
           job_id           |  status   | details |  job_type   | class_id | object_id |    object_name    |       start_time       |      update_time
----------------------------+-----------+---------+-------------+----------+-----------+-------------------+------------------------+------------------------
 wqhu6ewifze5xitg3umt24h5ua | completed |         | INDEX_BUILD |     1259 |     26433 | public.nt2_c1_idx | 2025-09-25 22:07:31+00 | 2025-09-25 22:07:46+00
```

[ステータス] 列には、次のいずれかの値を指定することができます。


| ステータス | 説明 | 
| --- | --- | 
| submitted | タスクは送信されましたが、Aurora DSQL はまだタスクの処理を開始していません。 | 
| processing | Aurora DSQL はタスクを処理しています。 | 
| failed | タスクが失敗しました。詳細については、[details] 列を参照してください。Aurora DSQL がインデックスの構築に失敗した場合、Aurora DSQL ではインデックス定義を自動的に削除しません。DROP INDEX コマンドを使用してインデックスを手動で削除する必要があります。 | 
| completed | Aurora DSQL はタスクを正常に完了しました。 | 

カタログテーブル `pg_index` および `pg_class` を使用して、インデックスの状態をクエリすることもできます。具体的には、属性 `indisvalid` と `indisimmediate` により、インデックスの状態を知ることができます。Aurora DSQL がインデックスを作成する間、初期ステータスは `INVALID` です。インデックスの `indisvalid` フラグは、`FALSE` または `f` を返します。これはインデックスが有効でないことを示します。フラグが `TRUE` または `t` を返すと、インデックスは準備完了です。

```
SELECT relname AS index_name, indisvalid as is_valid, pg_get_indexdef(indexrelid) AS index_definition
from pg_index, pg_class
WHERE pg_class.oid = indexrelid AND indrelid = 'test.departments'::regclass;
```

```
    index_name    | is_valid |                                                 index_definition                                                  
------------------+----------+-------------------------------------------------------------------------------------------------------------------
 department_pkey  |     t    | CREATE UNIQUE INDEX department_pkey ON test.departments USING btree_index (title) INCLUDE (name, manager, size)
 test_index1      |     t    | CREATE INDEX test_index1 ON test.departments USING btree_index (name, manager, size)
```

## 一意のインデックスビルドの失敗
<a name="unique-index-failures"></a>

非同期の一意インデックスビルドジョブが詳細 `Found duplicate key while validating index for UCVs` で失敗状態を示している場合、これは一意性の制約違反のために一意インデックスを構築できなかったことを示します。

**一意のインデックスビルドの失敗を解決するには**

1. 一意のセカンダリインデックスで指定されたキーのエントリが重複しているプライマリテーブルの行を削除します。

1. 失敗したインデックスを削除します。

1. 新しいインデックス作成コマンドを発行します。

## プライマリテーブルでの一意性違反の検出
<a name="detect-uniqueness-violation"></a>

次の SQL クエリは、テーブルの指定された列で重複する値を識別するのに役立ちます。これは、現在プライマリキーとして設定されていない列や、ユーザーテーブルの E メールアドレスなどの一意の制約がない列に一意性を適用する必要がある場合に特に便利です。

 以下の例は、サンプルユーザーテーブルを作成し、既知の重複を含むテストデータを入力してから、検出クエリを実行する方法を示しています。

**テーブルスキーマを定義する**

```
-- Drop the table if it exists
DROP TABLE IF EXISTS users;

-- Create the users table with a simple integer primary key
CREATE TABLE users (
    user_id INTEGER PRIMARY KEY,
    email VARCHAR(255),
    first_name VARCHAR(100),
    last_name VARCHAR(100),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
```

**重複する E メールアドレスのセットを含むサンプルデータを挿入する**

```
-- Insert sample data with explicit IDs
INSERT INTO users (user_id, email, first_name, last_name) VALUES
    (1, 'john.doe@example.com', 'John', 'Doe'),
    (2, 'jane.smith@example.com', 'Jane', 'Smith'),
    (3, 'john.doe@example.com', 'Johnny', 'Doe'),
    (4, 'alice.wong@example.com', 'Alice', 'Wong'),
    (5, 'bob.jones@example.com', 'Bob', 'Jones'),
    (6, 'alice.wong@example.com', 'Alicia', 'Wong'),
    (7, 'bob.jones@example.com', 'Robert', 'Jones');
```

**重複検出のクエリを実行する**

```
-- Query to find duplicates
WITH duplicates AS (
    SELECT email, COUNT(*) as duplicate_count
    FROM users
    GROUP BY email
    HAVING COUNT(*) > 1
)
SELECT u.*, d.duplicate_count
FROM users u
INNER JOIN duplicates d ON u.email = d.email
ORDER BY u.email, u.user_id;
```

**重複した E メールアドレスを持つすべてのレコードを表示する**

```
 user_id |         email          | first_name | last_name |         created_at         | duplicate_count 
---------+------------------------+------------+-----------+----------------------------+-----------------
       4 | akua.mansa@example.com | Akua       | Mansa     | 2025-05-21 20:55:53.714432 |               2
       6 | akua.mansa@example.com | Akua       | Mansa     | 2025-05-21 20:55:53.714432 |               2
       1 | john.doe@example.com   | John       | Doe       | 2025-05-21 20:55:53.714432 |               2
       3 | john.doe@example.com   | Johnny     | Doe       | 2025-05-21 20:55:53.714432 |               2
(4 rows)
```

**ここでインデックス作成ステートメントを試すと、失敗します。**

```
postgres=> CREATE UNIQUE INDEX ASYNC idx_users_email ON users(email);
      job_id      
----------------------------
 ve32upmjz5dgdknpbleeca5tri
(1 row)

postgres=> select * from sys.jobs;
           job_id           |  status   |                       details                       |  job_type   | class_id | object_id |      object_name       |       start_time       |      update_time       
----------------------------+-----------+-----------------------------------------------------+-------------+----------+-----------+------------------------+------------------------+------------------------
 qpn6aqlkijgmzilyidcpwrpova | completed |                                                     | DROP        |     1259 |     26384 |                        | 2025-05-20 00:47:10+00 | 2025-05-20 00:47:32+00
 ve32upmjz5dgdknpbleeca5tri | failed    | Found duplicate key while validating index for UCVs | INDEX_BUILD |     1259 |     26396 | public.idx_users_email | 2025-05-20 00:49:49+00 | 2025-05-20 00:49:56+00
(2 rows)
```