0

Peoples テーブルの不要なデータを削除するツールとして Web アプリケーションを作成しました。このアプリケーションは主に、選挙権を得るために有効な人々のすべてのデータをフィルタリングするためのものです。最初は、メイン テーブルにまだ行がほとんどない場合は問題ありませんでしたが、テーブルが約 200K 行でいっぱいになると非常に悪い (6 秒) (テーブルが最大 600 万行になるため、さらに悪化します)。 .

私は以下のようなテーブル設計をしており、4 つのテーブル (州、市、区、町から始まる地域テーブル) を結合しています。各地域テーブルは、独自の ID で相互に関連付けられています。

CREATE TABLE `peoples` (
    `id` mediumint(8) unsigned NOT NULL AUTO_INCREMENT,
    `id_prov` smallint(2) NOT NULL,
    `id_city` smallint(2) NOT NULL,
    `id_district` smallint(2) NOT NULL,
    `id_town` smallint(4) NOT NULL,
    `tps` smallint(4) NOT NULL,
    `urut_xls` varchar(20) NOT NULL,
    `nik` varchar(20) NOT NULL,
    `name` varchar(60) NOT NULL,
    `place_of_birth` varchar(60) NOT NULL,
    `birth_date` varchar(30) NOT NULL,
    `age` tinyint(3) NOT NULL DEFAULT '0',
    `sex` varchar(20) NOT NULL,
    `marital_s` varchar(20) NOT NULL,
    `address` varchar(160) NOT NULL,
    `note` varchar(60) NOT NULL,
    `m_name` tinyint(1) NOT NULL DEFAULT '0',
    `m_birthdate` tinyint(1) NOT NULL DEFAULT '0' ,
    `format_birthdate` tinyint(1) NOT NULL DEFAULT '0' ,
    `m_sex` tinyint(1) NOT NULL DEFAULT '0' COMMENT ,
    `m_m_status` tinyint(1) NOT NULL DEFAULT '0' ,
    `sex_double` tinyint(1) NOT NULL DEFAULT '0',
    `id_import` bigint(10) NOT NULL,
    `id_workspace` tinyint(4) unsigned NOT NULL DEFAULT '0',
    `stat_valid` smallint(1) NOT NULL DEFAULT '0' ,
    `add_manual` tinyint(1) unsigned NOT NULL DEFAULT '0' ,
    `insert_by` varchar(12) NOT NULL,
    `update_by` varchar(12) DEFAULT NULL,
    `mark_as_duplicate` smallint(1) NOT NULL DEFAULT '0' ,
    `mark_as_trash` smallint(1) NOT NULL DEFAULT '0' ,
    `in_date_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
    PRIMARY KEY (`id`),
    KEY `ind_import` (`id_import`),
    KEY `ind_duplicate` (`mark_as_duplicate`),
    KEY `id_workspace` (`id_workspace`),
    KEY `tambah_manual` (`tambah_manual`),
    KEY `il` (`stat_valid`,`mark_as_trash`,`in_date_time`),
    KEY `region` (`id_prov`,`id_kab`,`id_kec`,`id_kel`,`tps`),
    KEY `name` (`name`),
    KEY `place_of_birth` (`place_of_birth`),
    KEY `ind_birth` (`birthdate`(10)),
    KEY `ind_sex` (`sex`(2))
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;

街:

CREATE TABLE `town` (
    `id` smallint(4) NOT NULL,
    `id_district` smallint(2) NOT NULL,
    `id_city` smallint(2) NOT NULL,
    `id_prov` smallint(2) NOT NULL,
    `name_town` varchar(60) NOT NULL,
    `handprint` blob,
    `pps_1` varchar(60) DEFAULT NULL,
    `pps_2` varchar(60) DEFAULT NULL,
    `pps_3` varchar(60) DEFAULT NULL,
    `tpscount` smallint(2) DEFAULT NULL,
    `pps_4` varchar(60) DEFAULT NULL,
    `pps_5` varchar(60) DEFAULT NULL,
    PRIMARY KEY (`id_prov`,`id_kab`,`id_kec`,`id`),
    KEY `name_town` (`name_town`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

そして次のようなクエリ

SELECT `E`.`id`, `E`.`id_prov`, `E`.`id_city`, `E`.`id_district`, `E`.`id_town`, 
  `B`.`name_prov`,`C`.`name_city`,`D`.`name_district`, `A`.`name_town`,
  `E`.`tps`, `E`.`urut_xls`, `E`.`nik`,`E`.`name`,`E`.`place_of_birth`,
  `E`.`birth_date`, `E`.age, `E`.`sex`,   `E`.`marital_s`, `E`.`address`,
  `E`.`note` 
FROM peoples E
JOIN test_prov B ON  E.id_prov = B.id
JOIN test_city C ON E.id_city = C.id 
    AND (C.id_prov=B.id)
JOIN test_district D ON E.id_district = D.id 
    AND ((D.id_city = C.id) AND (D.id_prov= B.id))
JOIN test_town A ON E.id_town = A.id 
    AND ((A.id_district = D.id) 
    AND (A.id_city = C.id) 
    AND (A.id_prov = B.id)) 
    AND E.stat_valid=1 
    AND E.mark_as_trash=0

mark_as_trash は、データが削除されたレコードとしてマークされているかどうかを知るためだけに 1 と 0 のみを含むマーク列であり、stat_valid はフィルタリングされた結果値です。値が 1 の場合、データは選択権を取得するために有効です。

説明を見ようとしましたが、インデックス ルックアップとして使用される列はありません。これが、アプリケーションが 200K 行で非常に遅い理由だと思います。上記のクエリは 2 つの条件のみを示していますが、アプリケーションには、名前、出生地、生年月日、年齢、範囲などでフィルター処理する機能があります。

どうすればこのパフォーマンスを向上させることができますか?

4

1 に答える 1

0

1 つの都市が 2 つの州にまたがることはできますか? そうでない場合、1行だけを提供する必要があるかC.id_prov=B.idどうかを確認するのはなぜですか?E.id_city = C.id

また、20 万行を選択しているため、クエリが遅いようです。インデックスはパフォーマンスを向上させますが、一度にすべての行が本当に必要ですか? ページネーション (制限、オフセット) を使用する必要があります。

于 2013-06-02T19:06:27.677 に答える