0

250 万人の医師のリストを含むテーブルがあります。また、受け入れられた保険、話されている言語、および提供されている専門分野 (分類法) の表もあります。医師のテーブルは次のようになります。

CREATE TABLE `doctors` (
  `doctor_id` int(10) NOT NULL AUTO_INCREMENT,
  `city_id` int(10) NOT NULL DEFAULT '0',
  `d_gender` char(1) NOT NULL DEFAULT 'U',
  `s_insurance` int(6) NOT NULL DEFAULT '0',
  `s_languages` int(6) NOT NULL DEFAULT '0',
  `s_taxonomy` int(6) NOT NULL DEFAULT '0',
  PRIMARY KEY (`doctor_id`)
) ENGINE=InnoDB;

その他の情報は次のように保存されます。

CREATE TABLE `doctors_insurance` (
  `assoc_id` int(10) NOT NULL AUTO_INCREMENT,
  `doctor_id` int(10) NOT NULL DEFAULT '0',
  `insurance_id` int(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`assoc_id`)
) ENGINE=InnoDB;

CREATE TABLE `doctors_languages` (
  `assoc_id` int(10) NOT NULL AUTO_INCREMENT,
  `doctor_id` int(10) NOT NULL DEFAULT '0',
  `language_id` int(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`assoc_id`)
) ENGINE=InnoDB;

CREATE TABLE `doctors_taxonomy` (
  `assoc_id` int(10) NOT NULL AUTO_INCREMENT,
  `doctor_id` int(10) NOT NULL DEFAULT '0',
  `taxonomy_id` int(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`assoc_id`)
) ENGINE=InnoDB;

当然のことながら、各医師はさまざまな異なる保険プランをサポートしており、おそらく複数の言語を話し、一部の医師は複数の異なる専門分野 (分類法) を持っている場合があります。そのため、インデックス作成用に別のテーブルを用意することにしました。この方法では、新しいインデックスを追加するか、古いインデックスを削除する必要があります。テーブルを削除するだけで済み、昔ながらの方法で実際に行うのに長い時間を待つ必要はありません。

また、将来的には他のスケーリング手法を検討する必要があるため、従来の JOIN は今のところ私には何の違いもないので、心配していません。

名前による索引付けは簡単でした:

CREATE TABLE `indices_doctors_names` (
  `ref_id` int(10) NOT NULL AUTO_INCREMENT,
  `doctor_id` int(10) NOT NULL DEFAULT '0',
  `practice_id` int(10) NOT NULL DEFAULT '0',
  `name` varchar(120) NOT NULL DEFAULT '',
  PRIMARY KEY (`ref_id`),
  KEY `name` (`name`)
) ENGINE=InnoDB;

しかし、人々が都市、専門分野、保険、言語、性別、その他の人口統計で検索できるようにしたかったとき、私は彼を作成しました:

CREATE TABLE `indices_doctors_demos` (
  `ref_id` int(10) NOT NULL AUTO_INCREMENT,
  `doctor_id` int(10) NOT NULL DEFAULT '0',
  `city_id` int(10) NOT NULL DEFAULT '0',
  `taxonomy_id` int(6) NOT NULL DEFAULT '0',
  `insurance_id` int(6) NOT NULL DEFAULT '0',
  `language_id` int(6) NOT NULL DEFAULT '0',
  `gender_id` char(1) NOT NULL DEFAULT 'U',
  PRIMARY KEY (`ref_id`),
  KEY `index` (`city_id`,`taxonomy_id`,`insurance_id`,`language_id`,`gender_id`)
) ENGINE=InnoDB;

アイデアは、主に専門分野、保険、または言語の変更ごとにエントリがあるということですが、他は同じです。これは明らかな問題を引き起こします。医師が 3 つの専門分野を持ち、3 つの保険会社をサポートし、3 つの言語を話す場合、これだけでも、この特定の医師には 27 のエントリがあることを意味します。したがって、250 万件のエントリは、はるかに多くのエントリに簡単に膨れ上がります。

これを行うためのより良いアプローチが必要ですが、どのように行うことができますか? 繰り返しますが、従来のインデックス作成手法に移行して JOIN を使用することには興味がありません。なぜなら、すぐに遅くなりすぎるからです。簡単にスケールアウトできる方法が必要です。

4

2 に答える 2

0

「indices_doctors_demos」のような非正規化テーブルでの行の爆発に対処する通常の方法は、5NF に正規化することです。正規化は、id 番号を代理キーとして使用するという決定とはまったく関係がないことに注意してください。

あなたが説明したシナリオでは、5NF への正規化が実用的です。約 700 万行を超えるテーブルはありません。テーブル「indices_doctors_demos」は完全に消失し、4 つの「doctors」テーブルはすべて狭くなり、それらすべてが非常に選択的なインデックスになってしまいます。

あなたが私のために働いていたら、別のアプローチを取る前に、5NF が機能しないことを証明する必要があります.

すでにすべてのデータがあるのでクエリ プランに細心の注意を払いながら、データを構築してテストすることは理にかなっています。午後1時間以上かかることはありません。いくつかのテーブル名を推測して、これらのテーブルにデータをロードすることをお勧めします。

-- You're missing foreign keys throughout. I've added some of them, 
-- but not all of them. I'm also assuming you have a way to identify 
-- doctors besides a bare integer.
CREATE TABLE `doctors` (
  `doctor_id` int(10) NOT NULL AUTO_INCREMENT,
  `city_id` int(10) NOT NULL DEFAULT '0',
  `d_gender` char(1) NOT NULL DEFAULT 'U',
  PRIMARY KEY (`doctor_id`)
) ENGINE=InnoDB;

CREATE TABLE `doctors_insurance` (
  `doctor_id` int(10) NOT NULL DEFAULT '0',
  `insurance_id` int(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`doctor_id`, `insurance_id`),
  FOREIGN KEY (`doctor_id`) REFERENCES `doctors` (`doctor_id`),
  FOREIGN KEY (`insurance_id`) REFERENCES `insurance` (`insurance_id`)
) ENGINE=InnoDB;

CREATE TABLE `doctors_languages` (
  `doctor_id` int(10) NOT NULL DEFAULT '0',
  `language_id` int(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`doctor_id`, `language_id`),
  FOREIGN KEY (`doctor_id`) REFERENCES `doctors` (`doctor_id`),
  FOREIGN KEY (`language_id`) REFERENCES `languages` (`language_id`)
) ENGINE=InnoDB;

CREATE TABLE `doctors_taxonomy` (
  `doctor_id` int(10) NOT NULL DEFAULT '0',
  `taxonomy_id` int(10) NOT NULL DEFAULT '0',
  PRIMARY KEY (`doctor_id`, `taxonomy_id`),
  FOREIGN KEY (`doctor_id`) REFERENCES `doctors` (`doctor_id`),
  FOREIGN KEY (`taxonomy_id`) REFERENCES `taxonomies` (`taxonomy_id`)
) ENGINE=InnoDB;
于 2012-08-07T12:29:15.277 に答える
0

これがあなたが探している答えではないことはわかっていますが、RDBM が実際にデータを理解して最適化するために使用できるのと同じメカニズムを使用して、RDBM がうまく機能することを自分で実装しようとしました。検索とクエリの両方。実際には、適切なインデックスの使用をやめて、独自の中途半端なソリューションを作成することを決定しました。これは、インデックス自体を実装しようとします (実際には、キーで RDBM のインデックス作成機能を使用します)。

すでに構造化されている方法でデータベースを実際に使用することをお勧めします。2.5m 行はそれほど多くの行ではなく、JOIN とインデックスの両方を使用して、制約内で高速に動作させることができるはずです。EXPLAIN を使用し、適切なインデックスを追加して、回答が必要なクエリをサポートします。問題が発生した場合 (ここでクエリを実行しているデータの量を考えると疑わしいと思います)、問題を解決しようとするのではなく、問題の可能性が実際にわかっているときに、ボトルネックを解決することを決定します。今まで想像しただけです。MySQL 以外にも役立つテクノロジがあるかもしれませんが、実際に何がパフォーマンスを低下させているのかを最初に知る必要があります。

于 2012-08-07T12:23:26.967 に答える