連絡先管理システムにMySQL RDMSを使用しています。現在、私のデータベースのサイズは大きくなり、100万を超えるレコードが含まれています。重複する電話番号の確認は、管理プロセス中に大きな問題になりました。データベース全体で電話番号を検索すると、サーバーの負荷が大幅に増加します。データベースに重複した電話レコードを保持したくないので、データベース全体で電話番号の存在を確認していたため、アプリケーションが少し遅くなっていました。私の質問:高性能でデータベース全体のクエリを改善するにはどうすればよいですか。
phone1 -> Datatype Varchar(10)
インデックス作成を試しましたが、少しはうまくいきました。システムのパフォーマンスを向上させるその他の方法。
テーブル構造:
CREATE TABLE `phone_directory` (
`lead_id` INT(9) UNSIGNED NOT NULL AUTO_INCREMENT,
`list_id` BIGINT(14) UNSIGNED DEFAULT NULL,
`gmt_offset_now` DECIMAL(4,2) DEFAULT '0.00',
`first_name` VARCHAR(30) DEFAULT NULL,
`middle_initial` CHAR(1) DEFAULT NULL,
`last_name` VARCHAR(30) DEFAULT NULL,
`address1` VARCHAR(100) DEFAULT NULL,
`address2` VARCHAR(100) DEFAULT NULL,
`address3` VARCHAR(100) DEFAULT NULL,
`city` VARCHAR(50) DEFAULT NULL,
`state` CHAR(2) DEFAULT NULL,
`postal_code` VARCHAR(10) DEFAULT NULL,
`phone1` VARCHAR(12) DEFAULT NULL,
`phone2` VARCHAR(12) DEFAULT NULL,
`phone3` VARCHAR(12) DEFAULT NULL,
`email` VARCHAR(70) DEFAULT NULL,
`fax_number` VARCHAR(255) DEFAULT NULL,
`manager_name` VARCHAR(255) DEFAULT NULL,
`status` VARCHAR(6) DEFAULT NULL,
PRIMARY KEY (`lead_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
クエリ:
SELECT * FROM phone_directory WHERE phone1 IN ('315XXXXXXX','0315XXXXXXX');
SELECT * FROM phone_directory WHERE phone2 IN ('315XXXXXXX','0315XXXXXXX');
SELECT * FROM phone_directory WHERE phone3 IN ('315XXXXXXX','0315XXXXXXX');
ないには3つの列phone1
、phone2
、phone3
を含めることをお勧めしますが、電話用の関連テーブル、データを完全に正規化(またはさらに正規化)します。
CREATE TABLE `phone_directory` (
`lead_id` INT(9) UNSIGNED NOT NULL AUTO_INCREMENT,
`list_id` BIGINT(14) UNSIGNED DEFAULT NULL,
`gmt_offset_now` DECIMAL(4,2) DEFAULT '0.00',
`first_name` VARCHAR(30) DEFAULT NULL,
`middle_initial` CHAR(1) DEFAULT NULL,
`last_name` VARCHAR(30) DEFAULT NULL,
`address1` VARCHAR(100) DEFAULT NULL,
`address2` VARCHAR(100) DEFAULT NULL,
`address3` VARCHAR(100) DEFAULT NULL,
`city` VARCHAR(50) DEFAULT NULL,
`state` CHAR(2) DEFAULT NULL,
`postal_code` VARCHAR(10) DEFAULT NULL,
`email` VARCHAR(70) DEFAULT NULL,
`fax_number` VARCHAR(255) DEFAULT NULL,
`manager_name` VARCHAR(255) DEFAULT NULL,
`status` VARCHAR(6) DEFAULT NULL,
PRIMARY KEY (`lead_id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
CREATE TABLE phones
(
lead_id INT(9) NOT NULL REFERENCES phone_directory(lead_id),
phone VARCHAR(12) NOT NULL,
priority tinyint DEFAULT 1, -- If you need to give them priorities (1, 2, 3, ...), or sort them
CONSTRAINT unique_phones UNIQUE(phone), -- You don't want repetead telephones. This enforces it.
PRIMARY KEY(lead_id, phone) -- Covering index + clustering... for the sake of efficiency
) ;
現在のチェックは次のとおりです。
SELECT
lead_id, phone
FROM
phones
WHERE
phone IN ('315XXXXXXX','0315XXXXXXX');
平均すると、これは3倍高速になります...また、特定のlead_id
に対して0、1、2、3、または任意の数の電話を使用でき、UNIQUE
制約一意性を適用するので、アプリケーションのある時点でエラーが発生した場合、データベースは間違いを回避するのに役立ちます。
dbfiddle ここ
注1:1つの会社が3つ以上の電話番号を持っていることは不思議ではありません:あなたはすべての拠点をカバーしています。
注2:電話番号では非ASCII文字を使用しないので、latin1_bin
などの単一文字の照合順序を指定することで、スペースを節約できます(移動するデータが少ないため、速度がわずかに上がります)。
dbfiddle ここ
まあ、これらのインデックスがあれば、何の問題もないはずです。テーブルには何行ありますか?
クエリで使用する結合の数。結合を使用している場合、それらのテーブルには適切なインデックスがありますか?
上記のクエリにはほとんど問題がありません。実行中の実際のクエリが遅い場合に投稿します。
それでも、もっと深く知りたいのであれば、私はいくつかのポイントを持っています。
注::クエリでのアスタリスクの使用はお勧めしません。
電話のフィールドにインデックスを作成し、それらを「null以外」に変更する必要があります。
ALTER TABLE `phone_directory` CHANGE `phone1` `phone1` VARCHAR( 12 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
CHANGE `phone2` `phone2` VARCHAR( 12 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
CHANGE `phone3` `phone3` VARCHAR( 12 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
ADD INDEX ( `phone1` ) ,
ADD INDEX ( `phone2` ) ,
ADD INDEX ( `phone3` )