データの挿入
このドキュメントでは、さまざまなプログラミング言語で SQL 言語を使用して TiDB にデータを挿入する方法について説明します。
始める前に
このドキュメントを読む前に、次のものを準備する必要があります。
行を挿入する
複数行のデータを挿入する方法は2つあります。例えば、 3人の選手のデータを挿入する必要がある場合などです。
複数行の挿入ステートメント:
INSERT INTO `player` (`id`, `coins`, `goods`) VALUES (1, 1000, 1), (2, 230, 2), (3, 300, 5);複数の単一行挿入ステートメント:
INSERT INTO `player` (`id`, `coins`, `goods`) VALUES (1, 1000, 1); INSERT INTO `player` (`id`, `coins`, `goods`) VALUES (2, 230, 2); INSERT INTO `player` (`id`, `coins`, `goods`) VALUES (3, 300, 5);
通常、 multi-line insertion statement single-line insertion statements倍数よりも速く実行されます。
CREATE TABLE `player` (`id` INT, `coins` INT, `goods` INT);
INSERT INTO `player` (`id`, `coins`, `goods`) VALUES (1, 1000, 1), (2, 230, 2);
この SQL の使用方法の詳細については、 TiDBクラスタへの接続参照し、クライアントを使用して TiDB クラスターに接続した後に SQL ステートメントを入力する手順に従ってください。
// ds is an entity of com.mysql.cj.jdbc.MysqlDataSource
try (Connection connection = ds.getConnection()) {
    connection.setAutoCommit(false);
    PreparedStatement pstmt = connection.prepareStatement("INSERT INTO player (id, coins, goods) VALUES (?, ?, ?)"))
    // first player
    pstmt.setInt(1, 1);
    pstmt.setInt(2, 1000);
    pstmt.setInt(3, 1);
    pstmt.addBatch();
    // second player
    pstmt.setInt(1, 2);
    pstmt.setInt(2, 230);
    pstmt.setInt(3, 2);
    pstmt.addBatch();
    pstmt.executeBatch();
    connection.commit();
} catch (SQLException e) {
    e.printStackTrace();
}
デフォルトの MySQL JDBCDriver設定により、一括挿入のパフォーマンスを向上させるにはいくつかのパラメータを変更する必要があります。
| パラメータ | 手段 | 推奨シナリオ | 推奨コンフィグレーション | 
|---|---|---|---|
useServerPrepStmts | サーバー側を使用して準備済みステートメントを有効にするかどうか | プリペアドステートメントを複数回使用する必要がある場合 | true | 
cachePrepStmts | クライアントが準備されたステートメントをキャッシュするかどうか | useServerPrepStmts=true | true | 
prepStmtCacheSqlLimit | プリペアドステートメントの最大サイズ(デフォルトでは 256 文字) | プリペアドステートメントが256文字を超える場合 | プリペアドステートメントの実際のサイズに応じて構成されます | 
prepStmtCacheSize | プリペアドステートメントキャッシュの最大数 (デフォルトでは 25) | 準備された文の数が25を超える場合 | 準備されたステートメントの実際の数に応じて構成されます | 
rewriteBatchedStatements | バッチステートメントを書き換えるかどうか | バッチ操作が必要な場合 | true | 
allowMultiQueries | バッチ操作を開始する | クライアントのバグ場合はrewriteBatchedStatements = trueとuseServerPrepStmts = trueときにこれを設定する必要があるため | true | 
MySQL JDBCDriverは統合設定も提供しています: useConfigs 。3 maxPerformance設定すると、設定セットを設定するのと同等になります。5 mysql:mysql-connector-java:8.0.28例に挙げると、 useConfigs=maxPerformanceは以下の内容が含まれます。
cachePrepStmts=true
cacheCallableStmts=true
cacheServerConfiguration=true
useLocalSessionState=true
elideSetAutoCommits=true
alwaysSendSetIsolation=false
enableQueryTimeouts=false
connectionAttributes=none
useInformationSchema=true
mysql-connector-java-{version}.jar!/com/mysql/cj/configurations/maxPerformance.propertiesチェックすると、対応するバージョンの MySQL JDBCDriverのuseConfigs=maxPerformanceに含まれる構成を取得できます。
以下はJDBC接続文字列の設定例です。この例では、ホスト: 127.0.0.1 、ポート: 4000 、ユーザー名: root 、パスワード: null、デフォルトデータベース: testです。
jdbc:mysql://127.0.0.1:4000/test?user=root&useConfigs=maxPerformance&useServerPrepStmts=true&prepStmtCacheSqlLimit=2048&prepStmtCacheSize=256&rewriteBatchedStatements=true&allowMultiQueries=true
Javaの完全な例については、以下を参照してください。
package main
import (
    "database/sql"
    "strings"
    _ "github.com/go-sql-driver/mysql"
)
type Player struct {
    ID    string
    Coins int
    Goods int
}
func bulkInsertPlayers(db *sql.DB, players []Player, batchSize int) error {
    tx, err := db.Begin()
    if err != nil {
        return err
    }
    stmt, err := tx.Prepare(buildBulkInsertSQL(batchSize))
    if err != nil {
        return err
    }
    defer stmt.Close()
    for len(players) > batchSize {
        if _, err := stmt.Exec(playerToArgs(players[:batchSize])...); err != nil {
            tx.Rollback()
            return err
        }
        players = players[batchSize:]
    }
    if len(players) != 0 {
        if _, err := tx.Exec(buildBulkInsertSQL(len(players)), playerToArgs(players)...); err != nil {
            tx.Rollback()
            return err
        }
    }
    if err := tx.Commit(); err != nil {
        tx.Rollback()
        return err
    }
    return nil
}
func playerToArgs(players []Player) []interface{} {
    var args []interface{}
    for _, player := range players {
        args = append(args, player.ID, player.Coins, player.Goods)
    }
    return args
}
func buildBulkInsertSQL(amount int) string {
    return "INSERT INTO player (id, coins, goods) VALUES (?, ?, ?)" + strings.Repeat(",(?,?,?)", amount-1)
}
Golangの完全な例については、以下を参照してください。
import MySQLdb
connection = MySQLdb.connect(
    host="127.0.0.1",
    port=4000,
    user="root",
    password="",
    database="bookshop",
    autocommit=True
)
with get_connection(autocommit=True) as connection:
    with connection.cursor() as cur:
        player_list = random_player(1919)
        for idx in range(0, len(player_list), 114):
            cur.executemany("INSERT INTO player (id, coins, goods) VALUES (%s, %s, %s)", player_list[idx:idx + 114])
Python の完全な例については、以下を参照してください。
一括挿入
大量のデータをTiDBクラスターに迅速にインポートする必要がある場合は、 PingCAPが提供するデータ移行ツールを使用することをお勧めします。3文INSERT使用は効率的ではなく、例外やその他の問題を自分で処理する必要があるため、最適な方法ではありません。
一括挿入に推奨されるツールは次のとおりです。
- データのエクスポート: Dumpling MySQL または TiDB データをローカルまたは Amazon S3 にエクスポートできます。
 
- データのインポート: TiDB Cloudコンソール中インポートの作成ページ。Dumplingでエクスポートしたデータ、ローカルCSVファイル、またはAmazon S3 または GCS からTiDB Cloudに CSV ファイルをインポートするをインポートできます。また、ローカルディスク、Amazon S3クラウドディスク、またはGCSクラウドディスクからのデータの読み取りもサポートしています。
 - データレプリケーション: TiDBデータ移行 . MySQL、MariaDB、Amazon AuroraデータベースをTiDBに複製できます。また、ソースデータベースからシャード化されたインスタンスとテーブルのマージと移行もサポートしています。
 - データのバックアップとリストア: TiDB Cloudコンソールのバックアップページ。Dumplingと比較して、バックアップとリストアはビッグデータシナリオに適しています。
 
ホットスポットを避ける
テーブルを設計する際には、挿入操作が多数発生するかどうかを考慮する必要があります。もしそうであれば、テーブル設計中にホットスポットを回避する必要があります。1 セクションを参照し、 主キーを選択 主キーを選択する際のルールに従ってください。
AUTO_RANDOM主キーを持つテーブルにデータを挿入する
挿入するテーブルの主キーに属性AUTO_RANDOMがある場合、デフォルトでは主キーを指定できません。例えば、データベースbookshopでは、 usersテーブルのフィールドidに属性AUTO_RANDOM含まれていることがわかります。
この場合、次のような SQL を使用して挿入することはできません。
INSERT INTO `bookshop`.`users` (`id`, `balance`, `nickname`) VALUES (1, 0.00, 'nicky');
エラーが発生します:
ERROR 8216 (HY000): Invalid auto random: Explicit insertion on auto_random column is disabled. Try to set @@allow_auto_random_explicit_insert = true.
挿入時にAUTO_RANDOM列を手動で指定することはお勧めしません。
このエラーを処理するには 2 つの解決策があります。
(推奨)挿入文からこの列を削除し、TiDBによって初期化された値
AUTO_RANDOM使用します。これはAUTO_RANDOMのセマンティクスに適合します。INSERT INTO `bookshop`.`users` (`balance`, `nickname`) VALUES (0.00, 'nicky');この列を指定する必要があることが確実な場合は、ユーザー変数を変更することで、挿入時に
SET文を使用してAUTO_RANDOM列を指定できるようにすることができます。SET @@allow_auto_random_explicit_insert = true; INSERT INTO `bookshop`.`users` (`id`, `balance`, `nickname`) VALUES (1, 0.00, 'nicky');
HTAPを使用する
TiDBでは、HTAP機能により、データ挿入時に追加の操作を実行する必要がなくなります。追加の挿入ロジックは不要です。TiDBはデータの一貫性を自動的に保証します。テーブル作成後に列指向レプリカ同期をオンにする実行するだけで、列指向レプリカを使用してクエリを直接高速化できます。
ヘルプが必要ですか?
不和またはスラック 、あるいはサポートチケットを送信するについてコミュニティに質問してください。