web-dev-qa-db-ja.com

MySQLクエリのパフォーマンスを向上させる-レコードが多すぎる

連絡先管理システムに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
Arun Kumar

ないには3つの列phone1phone2phone3を含めることをお勧めしますが、電話用の関連テーブル、データを完全に正規化(またはさらに正規化)します。

 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 ここ

1
joanolo

まあ、これらのインデックスがあれば、何の問題もないはずです。テーブルには何行ありますか?

クエリで使用する結合の数。結合を使用している場合、それらのテーブルには適切なインデックスがありますか?

上記のクエリにはほとんど問題がありません。実行中の実際のクエリが遅い場合に投稿します。

それでも、もっと深く知りたいのであれば、私はいくつかのポイントを持っています。

  1. 電話の文字がそれほど変わらない場合は、VARCHARの代わりにCHARを保持できます。 CHARフィールドに対するインデックスを使用したデータフェッチは、VARCHARフィールドよりも確実に高速です。
  2. これは、従業員/クライアントのマスターテーブルのようです。トランザクションを必要としない場合は、MyISAMを保持できます。これはInnoDBより高速です。
  3. ALTER TABLE tblname ROW_FORMAT = FIXED;これにより、VARCHARはCHARとして動作します。 (非推奨)。テーブルのサイズが大きくなります。

注::クエリでのアスタリスクの使用はお勧めしません。

0
Hytool

電話のフィールドにインデックスを作成し、それらを「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` ) 
0
Jehad Keriaki