0

MySQL/MariaDB データベースにインポートしたい 5 つのテキスト フィールドがあります。しかし、次の 2 つの問題があります。

(1) ファイルが非常に大きい: 0.5 GB から 10 GB
(2) 関連するキーはすべて 40 文字

ポイント(1) ありのままを受け入れなければならず、変えられない。ポイント2は私の懸念です。インターネットにはたくさんの提案があります。たとえば、varchar に enum を使用したり、数値サロゲートを使用したりします。テーブルに代理キーを追加しても問題ありません。ただし、同じ代理キーを他のテーブルに追加する必要があります。そして、これが私が立ち往生したポイントです。

ファイル/テーブルに関する特定の情報は次のとおりです。

  • 表の請求書には、3 つの列と 20 Mio 行があります。

    • 個別の値を持つinvoice_id (主キー) = 行数
    • 4,000 個の異なる値を持つ praxis_id
    • 4 Mio の個別の値を持つ患者 ID すべての列は CHAR(40) であり、固定長は 40 です。
  • テーブルdiagnosticには、3 つの列と 25 Mio 行があります。

    • Invoice_id CHAR(40) 1.4 Mio の個別の ID
    • 診断タイプ
    • 診断コード
  • テーブルの患者には、5 つの Mio 行を含む 5 つの列があります。

    • Patient_id CHAR(40) 一意ではありません (4 Mio の個別の pat_id)
    • praxis_id CHAR(40)
    • 生年月日、性別など

たとえば、請求書を診断と患者に結合したいとします。キーにインデックスを付けることは理にかなっています。1 つの方法は、invoice.invoice_id を主キーとして定義し、invoice テーブルの他のすべてのキーに対してインデックスを追加することです。テーブルの診断 (INDEX を含む invoice_id) と患者 (主キーとしてのpatient_id) と同じです。
問題は、以下を使用して、invoice.invoice_id を主キーとして定義するのに長い時間がかかったことです。

ALTER TABLE invoice_id ADD PRIMARY KEY(invoice_id);

1時間後、プロセスを強制終了しました。テーブルinvoiceのinvoice_idのデータ型の種類から、パフォーマンスの問題が1つ生じると思います。1 つのアイデアとして、テキスト ファイルをロードするときに自動インクリメント サロゲート キー Invoice_id_surr を追加することが考えられます。しかし、外部キーとして代理キーinvoice_id_surrを持たないテーブルdiagnosticのinvoice_idに参加する必要があるため、テーブルdiagnosticに参加したい場合は問題が残ります。diagnostic.invoice_id にインデックスを追加することもできますが、その場合、invoice テーブルに代理キーを持つ利点が失われます。

この問題に対処する方法に興味があります。結合できる既存のテーブルがいくつかありますが、キーは CHAR(40) であり、インデックスはありません。

手伝ってくれてありがとう。


更新 1: テーブル仕様
- キーには 40 文字 [0-9][AZ]があります
- これらはもう変更されないテーブルです (挿入なし)

-- invoice_id is primary key (unique)
-- patient_id and praxis id for foreign key and not unique in this table
CREATE TABLE invoice (
  invoice_id             CHAR(40) DEFAULT NULL
, praxis_id              CHAR(40) DEFAULT NULL
, patient_id             CHAR(40) DEFAULT NULL
, PRIMARY KEY (invoice_id2)
) ENGINE = InnoDB
;  

LOAD DATA LOCAL INFILE 'C:/data/invoice.txt'
INTO TABLE invoice
FIELDS TERMINATED BY '\t'
LINES TERMINATED BY '\r\n'
IGNORE 1 LINES
;

-- invoice_id is not unique in this table
CREATE TABLE diagnose (
  invoice_id             CHAR(40)    DEFAULT NULL
, diagnose_katalog       VARCHAR(20) DEFAULT NULL
, diagnose_code          VARCHAR(20) DEFAULT NULL
) ENGINE = InnoDB
;
-- patient_id is not unique in this table since since patient may change praxis
CREATE TABLE patient (
  patient_id             CHAR(40)    DEFAULT NULL
, praxis_id              CHAR(40)    DEFAULT NULL
, sex                    CHAR(1)     DEFAULT NULL
, birth_year             SMALLINT UNSIGNED DEFAULT NULL
, zip_code               VARCHAR(20) DEFAULT NULL
) ENGINE = InnoDB
;
4

3 に答える 3

1

さまざまな理由から、データベースの主キーとして自然キーを使用することは避けてください。これは、グーグルで簡単に見つけることができます。

また、「テーブルが与えられる」とはどういう意味ですか? テキスト ファイルとデータベース テーブルを 1 対 1 で対応させる必要はありません。代わりに、ニーズに最も適した方法でテーブルを設計する必要があります。ノーマライゼーションを目指します。

たとえばpatient_idpatient「テーブル」(ファイルのことですよね?) は一意ではないと言います。明らかに、患者が一意であるテーブルが必要です。patient_idしたがって、個別の属性を持つテーブルを作成します。patient_idそのテーブルの一意のキーである必要がありますが、そのテーブルの主キーとして機能する数値サロゲート (auto_increment フィールドなど) を生成します。その後、たとえば、一意のキーと主キーの数値サロゲートとしてpraxisテーブルを作成します。 次に、多対多の関係に応じて、3 番目のテーブルに接続praxis_idできます。このようにして、データベースを正規化します。属性を持つ患者は、常に 1 つのテーブル内の 1 つの行です。一方、同じ患者が現在のあなたに複数回入力されていますpatientpraxispatientpatient遅かれ早かれトラブルの原因となるファイル/テーブル。

于 2015-06-09T07:31:09.823 に答える
1

あなたは本当に持ってCHAR(40)VARCHAR(40)ますか?値は常に 40 文字ですか? テーブルCHARACTER SET utf8ですか?

CHAR(40) utf8常に120 バイトかかります。このようなフィールドに 'Z' を格納すると、1 バイトではなく 120 バイトが必要になります。40 文字をインポートする場合でも、それVARCHARを宣言すると、ロード時に末尾の空白が削除されます。

少なくとも、私はそうするだろう

ALTER TABLE foo
    MODIFY col1 VARCHAR(40) ...,  -- the "..." is other options for the col
    MODIFY col2 VARCHAR(40) ...,
    ...;

これはおそらく「ポイント(1)」を大いに助けるでしょう。そして、すべてを高速化します。(注意: その ALTER を完了するには長い時間がかかります。)

"自然な" PRIMARY KEY は悪ではありません。ただし、必要に応じて使用してください。あなたの場合、invoice_idはビジネス上の理由から一意である必要がありますよね? それはどのくらい長いですか?PKとしてはいいかも。

をしようとする前に、テーブルにどんな鍵がありましたALTERか? 最初にテーブルを作成するときは、少なくとも をPRIMARY KEY配置する必要があります。(しかし、今では遅すぎると思います。)

各テーブルに記入してくださいSHOW CREATE TABLE-- あまりにも多くの推測をしなければなりません.

サロゲート ( AUTO_INCREMENT) キーを追加すると、すべてのルックアップに間接的なレベルが追加されます。これにより、一部遅くなる可能性があります(多くのSELECTs変更が必要になることに加えて)。 SELECTs

テーブルにセカンダリ インデックスを追加するときは、使用しているSELECTステートメントに役立つものに基づいてください。これについては、私のindex cookbookで説明しています。SELECTs詳細な議論のためにここに提供してください。各列にやみくもにインデックスを追加しないでください。

forとinのように聞こえinvoice_idます。PRIMARY KEYinvoiceINDEXdiagnose

データを再ロードすることが実際的である場合は、フィールドVARCHARを 、 not CHAR、および have PRIMARY KEY(invoice_id)inで宣言しますinvoice

于 2015-06-10T15:53:38.577 に答える
0

私は自分の質問に答えます。この投稿の理由は、クエリを送信したためです。たとえば、主キーを定義するALTER TABLE ...と、数時間後にプロセスが停止しませんでした。@zgguvが述べたように、期間は妥当ではないようです。クエリを停止して再起動し (3 回目以降の場合もあります)、数分 (約 10 分) 後にプロセスが終了しました。クエリが時々ハングアップする理由がわかりません。これは今まで私に起こったことはありませんでしたが、私が使用したテーブルははるかに小さかった. 得られた教訓は次のとおりです。

  • 選択を高速化するには、長い文字列キーを数字キーに置き換える必要があります。

  • サイズが 10 GB のテーブル (テキストテーブル) の文字列キーをそれぞれ置き換えると、20 Mio の行番号が実現可能です (自分の髪を一度だけ引っ張る必要があります)。インデックス付き文字列キー間の結合には約 10 分かかりました。

  • クエリの所要時間が 30 フィート (ハングアップ) を超える場合は、クエリを停止して再試行してください。なぜこれが起こったのか (InnoDB、MyISAM、HeidiSQL など) を知っておくとよいでしょうが、これは別の問題です。

@zgguv サポートと忍耐に感謝します。

于 2015-06-10T14:10:04.150 に答える