📣
TiDB Cloud Premium はパブリックプレビュー中です。エンタープライズワークロード向けの無制限のスケーリング、即時の弾力性、高度なセキュリティを提供します。このページは自動翻訳されたものです。原文はこちらからご覧ください。

テーブルを作成する



このドキュメントでは、SQL文を使用してテーブルを作成する方法と、関連するベストプラクティスについて説明します。ベストプラクティスを説明するために、TiDBベースの書店アプリケーションの例を示します。

始める前に

この文書を読む前に、以下の作業が完了していることを確認してください。

テーブルとは何ですか

テーブル、TiDB の論理オブジェクトであり、 のデータベースオブジェクトです。SQL ステートメントから送信されたデータを格納するために使用されます。テーブルは、行と列の形式でデータレコードを保存します。テーブルには少なくとも 1 つの列があります。 n列を定義した場合、各データ行にはn列とまったく同じフィールドが含まれます。

テーブルの名前を挙げてください

テーブルを作成する最初のステップは、テーブルに名前を付けることです。将来、自分や同僚に大きな負担をかけるような、意味のない名前は使用しないでください。会社や組織のテーブル命名規則に従うことをお勧めします。

CREATE TABLEステートメントは通常、次の形式をとります。

CREATE TABLE {table_name} ( {elements} );

パラメータの説明

  • {table_name} : 作成するテーブルの名前。
  • {elements} : 列定義や主キー定義など、テーブル要素をカンマで区切ったリスト。

bookshopデータベースにユーザー情報を保存するためのテーブルを作成する必要があるとします。

まだ列が追加されていないため、以下のSQL文は実行できないことに注意してください。

CREATE TABLE `bookshop`.`users` ( );

列を定義する

はテーブルの下位要素です。各テーブルには少なくとも1つの列があります。列は、各行の値を単一のデータ型の小さなセルに分割することで、テーブルに構造を与えます。

カラム定義は通常、次の形式をとります。

{column_name} {data_type} {column_qualification}

パラメータの説明

  • {column_name} : 列名。
  • {data_type} : 列データ型
  • {column_qualification} :列レベルの制約生成された列列句などのカラム修飾。

usersテーブルに、一意の識別子idbalancenicknameなどの列を追加できます。

CREATE TABLE `bookshop`.`users` ( `id` bigint, `nickname` varchar(100), `balance` decimal(15,2) );

上記の記述では、 idという名前とタイプビギントを持つフィールドが定義されています。これは、一意のユーザー識別子を表すために使用されます。つまり、すべてのユーザー識別子はbigintタイプである必要があります。

次に、 nicknameという名前のフィールドが定義されます。これはvarchar型で、長さの制限は 100 文字です。つまり、ユーザーのnicknamesvarchar型を使用し、100 文字を超えないということです。

最後に、 balanceという名前のフィールドが追加されます。これは小数型で、精度15スケール2精度はフィールド内の桁数の合計を表し、スケールは小数点以下の桁数を表します。たとえば、 decimal(5,2)は、精度が5 、スケールが2で、範囲は-999.99から999.99となります。 decimal(6,1)は、精度が6 、スケールが1で、範囲が-99999.9から99999.9であることを意味します。decimal固定小数点型で、数値を正確に格納するために使用できます。正確な数値が必要なシナリオ (たとえば、ユーザー プロパティ関連) では、 decimal型を使用するようにしてください。

TiDB は、整数型浮動小数点型固定小数点型小数点型、日付と時刻の種類列挙型など、他の多くの列データ型をサポートしています。サポートされている列のデータ型を参照し、データベースに保存したいデータに一致するデータ型を使用できます。

もう少し複雑にするには、 booksデータの核となるbookshopテーブルを定義できます。 booksテーブルには、書籍の ID、タイトル、種類 (雑誌、小説、ライフ、芸術など)、在庫、価格、出版日などのフィールドが含まれます。

CREATE TABLE `bookshop`.`books` ( `id` bigint NOT NULL, `title` varchar(100), `type` enum('Magazine', 'Novel', 'Life', 'Arts', 'Comics', 'Education & Reference', 'Humanities & Social Sciences', 'Science & Technology', 'Kids', 'Sports'), `published_at` datetime, `stock` int, `price` decimal(15,2) );

このテーブルにはusersテーブルよりも多くのデータ型が含まれています。

  • 整数: ディスク使用量の過剰使用やパフォーマンスへの影響(型範囲が大きすぎる場合)またはデータオーバーフロー(データ型範囲が小さすぎる場合)を避けるため、適切なサイズの型を使用することをお勧めします。
  • :日時型は時間値を格納できます。
  • 列挙型: enum型は、限られた値の選択を格納するために使用できます。

主キーを選択

主キーとは、テーブル内の行を一意に識別する値を持つ、テーブル内の列または列のセットのことです。

注記:

TiDBにおけるプライマリキーのデフォルト定義は、 InnoDB (MySQLの一般的なstorageエンジン)における定義とは異なります。

  • InnoDBでは、プライマリキーは一意であり、nullではなく、インデックスはクラスタ化されています

  • TiDBでは、プライマリキーは一意であり、NULLであってはなりません。ただし、プライマリキーがクラスタ化インデックスであることは保証されていません。代わりに、別のキーワードセットCLUSTERED / NONCLUSTEREDによって、プライマリキーが**クラスタ化インデックス**であるかどうかが制御されます。キーワードが指定されていない場合は、システム変数@@global.tidb_enable_clustered_indexによって制御されます(化を参照クラスター化インデックス

主キーCREATE TABLEステートメントで定義されます。主キー制約制約付き列すべてに NULL 以外の値のみが含まれることを要求します。

テーブルは、主キーなし、または非整数の主キーを使用して作成できます。この場合、TiDB は暗黙の主キーとして_tidb_rowidを作成します。暗黙の主キー_tidb_rowid単調増加する性質を持つため、書き込み負荷の高いシナリオでは書き込みホットスポットが発生する可能性があります。したがって、アプリケーションが書き込み負荷の高い場合は、 SHARD_ROW_ID_BITSおよびPRE_SPLIT_REGIONSパラメータを使用してデータをシャーディングすることを検討してください。ただし、これにより読み取り増幅が発生する可能性があるため、トレードオフを独自に判断する必要があります。

テーブルの主キー整数型AUTO_INCREMENTが使用されている場合、 SHARD_ROW_ID_BITSを使用してもホットスポットを回避することはできません。ホットスポットを回避する必要があり、かつ連続的かつ増分的な主キーが必要ない場合は、 AUTO_INCREMENTの代わりにAUTO_RANDOMを使用して行 ID の連続性を排除できます。

TiDB セルフマネージドでホットスポットの問題を処理する方法の詳細については、ホットスポットの問題をトラブルシューティングする

主キーの選択に関するガイドラインに従って、次の例は、 AUTO_RANDOMの主キーがusersテーブルでどのように定義されるかを示しています。

CREATE TABLE `bookshop`.`users` ( `id` bigint AUTO_RANDOM, `balance` decimal(15,2), `nickname` varchar(100), PRIMARY KEY (`id`) );

クラスター化されているか否か

TiDB は v5.0 以降、クラスター化インデックス機能をサポートしています。この機能は、主キーを含むテーブルにデータを格納する方法を制御します。これにより、特定のクエリのパフォーマンスを向上できる方法でテーブルを編成する機能が TiDB に提供されます。

この文脈における「クラスタ化」という用語は、データの格納方法の構成を指し、連携して動作するデータベースサーバーのグループを指すものではありません。一部のデータベース管理システムでは、クラスタ化されたインデックステーブルをインデックス構成テーブル(IOT)と呼んでいます。

現在、TiDBの主キーを含むテーブルは、以下の2つのカテゴリに分類されます。

  • NONCLUSTERED : テーブルの主キーは非クラスター化インデックスです。非クラスター化インデックスを持つテーブルでは、行データのキーは、TiDB によって暗黙的に割り当てられる内部_tidb_rowidで構成されます。主キーは基本的に一意のインデックスであるため、非クラスター化インデックスを持つテーブルでは、行を格納するために少なくとも 2 つのキーと値のペアが必要です。それらは次のとおりです。
    • _tidb_rowid (キー) - 行データ(値)
    • 主キーデータ(キー) - _tidb_rowid (値)
  • CLUSTERED : テーブルの主キーはクラスタ化インデックスです。クラスタ化インデックスを持つテーブルでは、行データのキーはユーザーが指定した主キーデータで構成されます。したがって、クラスタ化インデックスを持つテーブルでは、行を格納するために必要なキーと値のペアは1つだけです。それは次のとおりです。
    • 主キーデータ(キー) - 行データ(値)

プライマリキーを選択で説明されているように、クラスター化インデックスは TiDB でキーワードCLUSTEREDおよびNONCLUSTEREDを使用して制御されます。

注記:

TiDB は、テーブルのPRIMARY KEYによるクラスタリングのみをサポートしています。クラスタ化インデックスが有効になっている場合、 { PRIMARY KEYクラスタ化インデックスという用語は同じ意味で使用されることがあります。 PRIMARY KEYは制約 (論理プロパティ) を指し、クラスタ化インデックスはデータの格納方法の物理的な実装を表します。

クラスター化インデックスを選択するためのガイドラインためのガイドラインに従って、次の例では、 booksusers } の間の関連付けを持つテーブルを作成します。これは、 ratings bookを表します。 users .この例では、テーブルを作成し、 book_iduser_idを使用して複合主キーを構築し、その主キークラスター化インデックスを作成します。

CREATE TABLE `bookshop`.`ratings` ( `book_id` bigint, `user_id` bigint, `score` tinyint, `rated_at` datetime, PRIMARY KEY (`book_id`,`user_id`) CLUSTERED );

列制約を追加する

主キー制約に加えて、TiDB はNULL不可制約、ユニークキー制約、およびDEFAULTなどの他の列制約もサポートします。完全な制約については、 TiDBの制約ドキュメントを参照してください。

デフォルト値を設定する

列にデフォルト値を設定するには、 DEFAULT制約を使用します。デフォルト値を使用すると、各列の値を指定せずにデータを挿入できます。

DEFAULT サポートされているSQL関数と組み合わせて使用​​できます。これにより、デフォルト値の計算をアプリケーションレイヤーから外すことで、アプリケーションレイヤーのリソースを節約できます。計算によって消費されたリソースは消滅せず、データベースによって処理されます。通常、デフォルト値を使用してデータを挿入できます。以下はratingsテーブルにデフォルト値を設定する例です。

CREATE TABLE `bookshop`.`ratings` ( `book_id` bigint, `user_id` bigint, `score` tinyint, `rated_at` datetime DEFAULT NOW(), PRIMARY KEY (`book_id`,`user_id`) CLUSTERED );

さらに、データ更新時に現在時刻もデフォルトで入力される場合は、以下のステートメントを使用できます(ただし、 ON UPDATEの後には、現在時刻に関連する式のみを入力できます)。

CREATE TABLE `bookshop`.`ratings` ( `book_id` bigint, `user_id` bigint, `score` tinyint, `rated_at` datetime DEFAULT NOW() ON UPDATE NOW(), PRIMARY KEY (`book_id`,`user_id`) CLUSTERED );

さまざまなデータ型のデフォルト値の詳細については、デフォルト値参照してください。

重複値を防止する

列内の重複値を防止する必要がある場合は、 UNIQUE制約を使用できます。

例えば、ユーザーのニックネームが一意であることを確認するには、 usersテーブルのテーブル作成 SQL ステートメントを次のように書き換えることができます。

CREATE TABLE `bookshop`.`users` ( `id` bigint AUTO_RANDOM, `balance` decimal(15,2), `nickname` varchar(100) UNIQUE, PRIMARY KEY (`id`) );

nicknameusersテーブルに挿入しようとすると、エラーが返されます。

null値を防止する

列にヌル値が含まれるのを防ぐ必要がある場合は、 NOT NULL制約を使用できます。

ユーザーのニックネームを例にとってみましょう。ニックネームが一意であるだけでなく、null でないことを確認するには、 usersテーブルを作成するための SQL ステートメントを次のように書き換えることができます。

CREATE TABLE `bookshop`.`users` ( `id` bigint AUTO_RANDOM, `balance` decimal(15,2), `nickname` varchar(100) UNIQUE NOT NULL, PRIMARY KEY (`id`) );

HTAP機能を使用する

注記:

このセクションで説明する手順は、クイック スタートとテストのみを目的としています。 TiDB での HTAP の使用法の詳細については、 HTAPを探索する参照してください。

ratingsアプリケーションを使用してbookshopテーブルに対して OLAP 分析を実行したいとします。たとえば、書籍の評価と評価のタイミングに有意な相関関係があるかどうかをクエリし、ユーザーによる書籍の評価が客観的かどうかを分析したいとします。この場合scoreフィールドとrated_at ratings } フィールドをクエリする必要があります。この操作は、OLTP 専用データベースではリソースを大量に消費します。または、ETL やその他のデータ同期ツールを使用して、OLTP データベースから専用の OLAP データベースにデータをエクスポートして分析することもできます。

このシナリオでは、OLTPとOLAPの両方のシナリオをサポートするHTAP(ハイブリッド・トランザクション・アンド・アナリティカル・プロセッシング)データベースであるTiDBが、理想的なワンストップデータベースソリューションとなります。

TiDBでは、オンライン・トランザクション処理(OLTP)には行ベースのstorageエンジンであるティクヴ、オンライン分析処理(OLAP)には列指向storageエンジンであるTiFlashを使用できます。設定後、 TiFlashはRaft Learnerコンセンサスアルゴリズムに従ってTiKVからリアルタイムでデータを複製し、TiKVとTiFlash間のデータの一貫性を厳密に確保します。

列ベースのデータを複製する

TiFlashはデプロイ後にデータを自動的に複製しません。そのため、複製するテーブルを手動で指定する必要があります。

ALTER TABLE {table_name} SET TIFLASH REPLICA {count};

パラメータの説明

  • {table_name} : テーブル名。
  • {count} : 複製されたレプリカの数。0 の場合、複製されたレプリカは削除されます。

TiFlash はテーブルを複製します。クエリが実行されると、TiDB はコストの最適化に基づいてクエリに対して TiKV (行ベース) またはTiFlash (列ベース) を自動的に選択します。あるいは、クエリでTiFlashレプリカを使用するかどうかを手動で指定できます。指定方法については、 TiDBを使用してTiFlashレプリカを読み取ります参照してください。

HTAP機能の使用例

ratingsテーブルは、 TiFlashの1レプリカを開きます。

ALTER TABLE `bookshop`.`ratings` SET TIFLASH REPLICA 1;

注記:

クラスターにTiFlashノードが含まれていない場合、この SQL ステートメントはエラー1105 - the tiflash replica count: 1 should be less than the total tiflash server count: 0を報告します。 TiDB Cloud Starterインスタンスを作成するを使用して、 TiFlashを含むTiDB Cloud Starterインスタンスを作成できます。

次に、以下のクエリを実行できます。

SELECT HOUR(`rated_at`), AVG(`score`) FROM `bookshop`.`ratings` GROUP BY HOUR(`rated_at`);

また、 EXPLAIN ANALYZEステートメントを実行して、このステートメントがTiFlashを使用しているかどうかを確認することもできます。

EXPLAIN ANALYZE SELECT HOUR(`rated_at`), AVG(`score`) FROM `bookshop`.`ratings` GROUP BY HOUR(`rated_at`);

実行結果:

+-----------------------------+-----------+---------+--------------+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+----------+------+ | id | estRows | actRows | task | access object | execution info | operator info | memory | disk | +-----------------------------+-----------+---------+--------------+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+----------+------+ | Projection_4 | 299821.99 | 24 | root | | time:60.8ms, loops:6, Concurrency:5 | hour(cast(bookshop.ratings.rated_at, time))->Column#6, Column#5 | 17.7 KB | N/A | | └─HashAgg_5 | 299821.99 | 24 | root | | time:60.7ms, loops:6, partial_worker:{wall_time:60.660079ms, concurrency:5, task_num:293, tot_wait:262.536669ms, tot_exec:40.171833ms, tot_time:302.827753ms, max:60.636886ms, p95:60.636886ms}, final_worker:{wall_time:60.701437ms, concurrency:5, task_num:25, tot_wait:303.114278ms, tot_exec:176.564µs, tot_time:303.297475ms, max:60.69326ms, p95:60.69326ms} | group by:Column#10, funcs:avg(Column#8)->Column#5, funcs:firstrow(Column#9)->bookshop.ratings.rated_at | 714.0 KB | N/A | | └─Projection_15 | 300000.00 | 300000 | root | | time:58.5ms, loops:294, Concurrency:5 | cast(bookshop.ratings.score, decimal(8,4) BINARY)->Column#8, bookshop.ratings.rated_at, hour(cast(bookshop.ratings.rated_at, time))->Column#10 | 366.2 KB | N/A | | └─TableReader_10 | 300000.00 | 300000 | root | | time:43.5ms, loops:294, cop_task: {num: 1, max: 43.1ms, proc_keys: 0, rpc_num: 1, rpc_time: 43ms, copr_cache_hit_ratio: 0.00} | data:TableFullScan_9 | 4.58 MB | N/A | | └─TableFullScan_9 | 300000.00 | 300000 | cop[tiflash] | table:ratings | tiflash_task:{time:5.98ms, loops:8, threads:1}, tiflash_scan:{dtfile:{total_scanned_packs:45, total_skipped_packs:1, total_scanned_rows:368640, total_skipped_rows:8192, total_rs_index_load_time: 1ms, total_read_time: 1ms},total_create_snapshot_time:1ms} | keep order:false | N/A | N/A | +-----------------------------+-----------+---------+--------------+---------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+------------------------------------------------------------------------------------------------------------------------------------------------+----------+------+

フィールドcop[tiflash]が表示された場合、タスクが処理のためにTiFlashに送信されることを意味します。

CREATE TABLE文を実行します。

上記のルールに従ってすべてのテーブルを作成した後、データベースデータベースの初期化スクリプトは次のようになります。テーブル情報を詳しく見たい場合は、 表の説明を参照してください。

データベース初期化スクリプトにinit.sqlという名前を付けて保存するには、次のステートメントを実行してデータベースを初期化します。

mysql -u root \ -h {host} \ -P {port} \ -p {password} \ < init.sql

bookshopデータベース配下のすべてのテーブルを表示するには、 SHOW TABLESステートメントを使用します。

SHOW TABLES IN `bookshop`;

実行結果:

+--------------------+ | Tables_in_bookshop | +--------------------+ | authors | | book_authors | | books | | orders | | ratings | | users | +--------------------+

テーブルを作成する際に従うべきガイドライン

このセクションでは、テーブルを作成する際に従うべきガイドラインを示します。

テーブル名を付ける際のガイドライン

  • 完全修飾テーブル名(例: CREATE TABLE {database_name}. {table_name} )を使用してください。データベース名を指定しない場合、TiDB はSQL セッションで現在使用されているデータベースを使用します。SQL セッションでデータベースを指定する際にUSE {databasename};を使用しない場合、TiDB はエラーを返します。
  • 意味のあるテーブル名を使用してください。たとえば、ユーザー テーブルを作成する必要がある場合は、 usert_userusersのような名前を使用するか、会社または組織の命名規則に従ってください。会社または組織に命名規則がない場合は、 テーブル命名規則を参照してください。 t1table1のようなテーブル名は使用しないでください。
  • 複数の単語はアンダースコアで区切られ、名前は32文字以内にすることをお勧めします。
  • 異なるビジネスモジュールのテーブル用に個別のDATABASEを作成し、それに応じてコメントを追加してください。

列を定義する際に従うべきガイドライン

  • 列のサポートデータ型を確認し、データ型の制約に従ってデータを整理してください。列に格納するデータに適した型を選択してください。
  • 主キーの選択に関する従うべきガイドラインを確認し、主キー列を使用するかどうかを決定します。
  • クラスタ化インデックスを選択するための従うべきガイドラインガイドラインを確認し、クラスタ化インデックスを指定するかどうかを決定してください。
  • 列制約を追加するチェックし、列に制約を追加するかどうかを決定します。
  • 意味のある列名を使用してください。会社または組織のテーブル命名規則に従うことをお勧めします。会社または組織に対応する命名規則がない場合は、 列名の命名規則を参照してください。

主キーを選択する際に従うべきガイドライン

  • テーブル内に主キーまたは一意インデックスを定義します。
  • 意味のある列を**主キー**として選択するようにしてください。
  • パフォーマンス上の理由から、幅の広いテーブルを保存することは避けてください。テーブルフィールドの数が60を超え、1行のデータの合計サイズが64K超えることは推奨されません。データ長が長すぎるフィールドは、別のテーブルに分割することをお勧めします。
  • 複雑なデータ型を使用することは推奨されません。
  • 結合するフィールドについては、データ型が一致していることを確認し、暗黙的な型変換を避けてください。
  • 単一の単調データ列に主キーを定義することは避けてください。単一の単調データ列(たとえば、 AUTO_INCREMENT属性を持つ列)を使用して主キーを定義すると、書き込みパフォーマンスに影響が出る可能性があります。可能であれば、 AUTO_RANDOMではなくAUTO_INCREMENT }を使用してください。これにより、主キーの連続性および増分属性が破棄されます。
  • 書き込み集中シナリオで単一の単調データ列にインデックスを作成する必要がある場合は、この単調データ列を主キーとして定義する代わりに、 AUTO_RANDOMを使用してそのテーブルの主キーを作成するか、 SHARD_ROW_ID_BITSPRE_SPLIT_REGIONSを使用して_tidb_rowidをシャーディングすることができます。

クラスター化インデックスを選択する際に従うべきガイドライン

  • クラスター化インデックスを構築するには、 主キーの選択に関するガイドラインに従ってください。

  • クラスター化インデックスを持たないテーブルと比較して、クラスター化インデックスを持つテーブルは、以下のシナリオにおいて、より優れたパフォーマンスとスループットのメリットを提供します。

    • データが挿入される際、クラスタ化インデックスによって、ネットワークからのインデックスデータの書き込み回数が1回削減されます。
    • 同等の条件を持つクエリが主キーのみに関係する場合、クラスタ化インデックスによってネットワークからのインデックスデータの読み取り回数が1回削減されます。
    • 範囲条件を含むクエリが主キーのみに関係する場合、クラスタ化インデックスはネットワークからのインデックスデータの読み取り回数を削減します。
    • 同等条件または範囲条件を含むクエリが主キーのプレフィックスのみに関係する場合、クラスタ化インデックスはネットワークからのインデックスデータの複数回の読み取りを削減します。
  • 一方、クラスター化インデックスを持つテーブルには、次のような問題が発生する可能性があります。

    • 近い値を持つ主キーを多数挿入すると、書き込みホットスポットの問題が発生する可能性があります。 主キーを選択する際に従うべきガイドラインてください。
    • 主キーのデータ型が64ビットより大きい場合、特にセカンダリインデックスが複数存在する場合は、テーブルデータがより多くのstorage容量を消費します。
  • クラスター化インデックスを使用するかどうかのデフォルトの動作を制御するには、システム変数@@global.tidb_enable_clustered_indexと構成alter-primary-key } を使用する代わりに、クラスター化インデックスを使用するかどうかを明示的に指定できます。

CREATE TABLE文を実行する際に従うべきガイドライン

  • データベーススキーマの変更にクライアント側のDriverやORMを使用することは推奨されません。データベーススキーマの変更にはMySQLクライアントまたはGUIクライアントを使用することをお勧めします。このドキュメントでは、ほとんどのシナリオでSQLファイルを渡してデータベーススキーマを変更するためにMySQLクライアントを使用します。
  • SQL 開発テーブルの作成と削除に関する仕様従ってください。ビジネスアプリケーション内にbuild文とdelete文をラップして判定ロジックを追加することを推奨します。

あと一歩

このドキュメントで作成されたすべてのテーブルにはセカンダリ インデックスが含まれていないことに注意してください。セカンダリ インデックスを追加するガイドについては、 セカンダリインデックスの作成を参照してください。

お困りですか?

このページは役に立ちましたか?