2017-10-10 10 views
0

私は 'map_item'のユーザー検索に使用される非常に大きなクエリを持っています。多くの左結合による単純なクエリの最適化

'map_item'には合計5399個のレコードがあり、結合されたテーブルのデータはまったく多くありません。

左の結合なしでこのクエリを実行すると(SELECT map_item_name FROM map_item)、期待通りに0.00sで返されますが、結合による上記のクエリは約10.00sかかります。

ユーザーは検索に適用できるフィルタが異なるため、クエリにはすべての左結合が必要ですが、元のクエリは実行に長時間(20秒程度)かかっていましたが、クエリのほとんどの部分は上記のまま残されていましたが(これはちょうど左の結合です)、これでも18秒かかります。ここで

は、クエリからの説明文です:

+----+-------------+-------------------+--------+----------------------------------+----------------------------------+---------+-----------------------------------------------------------+------+-----------------------------------------------------------------+ 
| id | select_type | table    | type | possible_keys     | key        | key_len | ref              | rows | Extra               | 
+----+-------------+-------------------+--------+----------------------------------+----------------------------------+---------+-----------------------------------------------------------+------+-----------------------------------------------------------------+ 
| 1 | SIMPLE  | map_item   | ALL | NULL        | NULL        | NULL | NULL              | 5455 | NULL               | 
| 1 | SIMPLE  | map_section_item | index | NULL        | map_section_item_section_id  | 8  | NULL              | 5330 | Using where; Using index; Using join buffer (Block Nested Loop) | 
| 1 | SIMPLE  | map_section  | eq_ref | PRIMARY       | PRIMARY       | 4  | bestmeal.map_section_item.map_section_item_section_id  | 1 | NULL               | 
| 1 | SIMPLE  | map_item_flag  | ALL | NULL        | NULL        | NULL | NULL              | 1509 | Using where; Using join buffer (Block Nested Loop)    | 
| 1 | SIMPLE  | flag    | eq_ref | PRIMARY       | PRIMARY       | 4  | bestmeal.map_item_flag.map_item_flag_flag_id    | 1 | Using index              | 
| 1 | SIMPLE  | map    | eq_ref | PRIMARY       | PRIMARY       | 4  | bestmeal.map_section.map_section_map_id     | 1 | Using index              | 
| 1 | SIMPLE  | place_map   | index | NULL        | branch_map_branch_id    | 8  | NULL              | 1275 | Using where; Using index; Using join buffer (Block Nested Loop) | 
| 1 | SIMPLE  | place    | eq_ref | PRIMARY       | PRIMARY       | 4  | bestmeal.place_map.place_map_place_id      | 1 | NULL               | 
| 1 | SIMPLE  | place_category | ref | place_category_place_id   | place_category_place_id   | 4  | bestmeal.place.place_id         | 1 | Using index              | 
| 1 | SIMPLE  | category   | eq_ref | PRIMARY       | PRIMARY       | 4  | bestmeal.place_category.place_category_category_id  | 1 | Using index              | 
| 1 | SIMPLE  | review   | ref | review_map_item_id    | review_map_item_id    | 4  | bestmeal.map_item.map_item_id        | 1 | Using index              | 
| 1 | SIMPLE  | map_price   | ref | map_price_item_id    | map_price_item_id    | 4  | bestmeal.map_item.map_item_id        | 1 | Using index              | 
| 1 | SIMPLE  | county_list  | eq_ref | PRIMARY       | PRIMARY       | 4  | bestmeal.place.place_address_county      | 1 | Using index              | 
+----+-------------+-------------------+--------+----------------------------------+----------------------------------+---------+-----------------------------------------------------------+------+-----------------------------------------------------------------+ 

これらのすべては、インデックスフィールドに対して行われた結合、および結合されたテーブルのいずれの代わりに使用することができ、それらのいずれかの不要なインデックスを持っていません意図するインデックス

私はクエリの最適化について専門家ではありませんが、私は左の結合を維持しながらこのクエリを高速化するためにできることを考え出すのには苦労しています。私はまた、実際に結合を使用せずに同じ結果を返す代替ソリューションを考えることはできません。

このクエリのパフォーマンスを向上させるのに役立つアイデアや、より速く、より速い方法でユーザーの検索を達成するためのアイデアはありますか?

編集要求されるように 表構造:これらの行で

CREATE TABLE `map_item` (
    `map_item_id` int(11) NOT NULL AUTO_INCREMENT, 
    `map_item_account_id` int(11) NOT NULL DEFAULT '0', 
    `map_item_category_id` int(11) NOT NULL, 
    `map_item_name` varchar(255) DEFAULT NULL, 
    `map_item_description` text, 
    `map_item_tags` varchar(255) DEFAULT NULL, 
    `map_item_type` set('d','f') DEFAULT NULL, 
    PRIMARY KEY (`map_item_id`), 
    KEY `map_item_account_id` (`map_item_account_id`), 
    KEY `map_item_tags` (`map_item_tags`), 
    KEY `map_item_category_id` (`map_item_category_id`), 
    FULLTEXT KEY `map_item_keyword_search` (`map_item_name`,`map_item_description`,`map_item_tags`), 
    FULLTEXT KEY `map_item_name` (`map_item_name`), 
    FULLTEXT KEY `map_item_description` (`map_item_description`), 
    FULLTEXT KEY `map_item_tags_2` (`map_item_tags`) 
) ENGINE=InnoDB AUTO_INCREMENT=5420 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `map_section_item` (
    `map_section_item_id` int(11) NOT NULL AUTO_INCREMENT, 
    `map_section_item_section_id` int(11) NOT NULL DEFAULT '0', 
    `map_section_item_item_id` int(11) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`map_section_item_id`), 
    KEY `map_section_item_section_id` (`map_section_item_section_id`,`map_section_item_item_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=24410 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `map_section` (
    `map_section_id` int(11) NOT NULL AUTO_INCREMENT, 
    `map_section_map_id` int(11) NOT NULL DEFAULT '0', 
    `map_section_map_draft_id` int(11) NOT NULL DEFAULT '0', 
    `map_section_column` tinyint(1) NOT NULL DEFAULT '1', 
    `map_section_name` varchar(255) DEFAULT NULL, 
    `map_section_description` text, 
    PRIMARY KEY (`map_section_id`), 
    KEY `map_section_map_draft_id` (`map_section_map_draft_id`), 
    KEY `map_section_map_id` (`map_section_map_id`), 
    FULLTEXT KEY `index_name` (`map_section_name`) 
) ENGINE=InnoDB AUTO_INCREMENT=4254 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `map_item_flag` (
    `map_item_flag_id` int(11) NOT NULL AUTO_INCREMENT, 
    `map_item_flag_item_id` int(11) NOT NULL DEFAULT '0', 
    `map_item_flag_flag_id` int(11) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`map_item_flag_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=1547 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `flag` (
    `flag_id` int(11) NOT NULL AUTO_INCREMENT, 
    `flag_category_id` int(11) NOT NULL DEFAULT '0', 
    `flag_name` varchar(255) DEFAULT NULL, 
    `flag_description` varchar(255) DEFAULT NULL, 
    `flag_img` varchar(255) DEFAULT NULL, 
    `flag_order` tinyint(2) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`flag_id`), 
    KEY `flag_category_id` (`flag_category_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `map` (
    `map_id` int(11) NOT NULL AUTO_INCREMENT, 
    `map_account_id` int(11) NOT NULL DEFAULT '0', 
    `map_name` varchar(255) DEFAULT NULL, 
    `map_description` text, 
    `map_type` set('d','f') DEFAULT NULL, 
    `map_layout` set('columns','tabs','collapsed') DEFAULT NULL, 
    PRIMARY KEY (`map_id`), 
    KEY `map_account_id` (`map_account_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=138 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `place_map` (
    `place_map_id` int(11) NOT NULL AUTO_INCREMENT, 
    `place_map_place_id` int(11) NOT NULL DEFAULT '0', 
    `place_map_map_id` int(11) NOT NULL DEFAULT '0', 
    `place_map_active` tinyint(1) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`place_map_id`), 
    KEY `branch_map_branch_id` (`place_map_place_id`,`place_map_map_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=2176 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `place` (
    `place_id` int(11) NOT NULL AUTO_INCREMENT, 
    `place_account_id` int(11) NOT NULL DEFAULT '0', 
    `place_name` varchar(120) DEFAULT NULL, 
    `place_alias` varchar(255) DEFAULT NULL, 
    `place_description` text, 
    `place_address_line_one` varchar(100) DEFAULT NULL, 
    `place_address_line_two` varchar(100) DEFAULT NULL, 
    `place_address_line_three` varchar(100) DEFAULT NULL, 
    `place_address_town` varchar(100) DEFAULT NULL, 
    `place_address_county` int(11) NOT NULL DEFAULT '0', 
    `place_address_postcode` varchar(10) DEFAULT NULL, 
    `place_address_latitude` decimal(11,8) DEFAULT NULL, 
    `place_address_longitude` decimal(11,8) DEFAULT NULL, 
    `place_phone` varchar(20) DEFAULT NULL, 
    `place_email` varchar(255) DEFAULT NULL, 
    `place_website` varchar(120) DEFAULT NULL, 
    `place_flag_initial_email` tinyint(1) NOT NULL DEFAULT '0', 
    `place_audit_admin_id` int(11) NOT NULL DEFAULT '0', 
    `place_last_audit_datetime` datetime DEFAULT NULL, 
    `place_created_by_admin_id` int(11) NOT NULL DEFAULT '0', 
    `place_created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `place_tried_google` int(1) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`place_id`), 
    KEY `place_account_id` (`place_account_id`), 
    KEY `place_address_county` (`place_address_county`), 
    KEY `place_alias` (`place_alias`), 
    KEY `place_audit_admin_id` (`place_audit_admin_id`), 
    KEY `place_created_by_admin_id` (`place_created_by_admin_id`), 
    FULLTEXT KEY `place_name` (`place_name`), 
    FULLTEXT KEY `place_keyword_search` (`place_name`,`place_address_town`), 
    FULLTEXT KEY `place_address_town` (`place_address_town`) 
) ENGINE=InnoDB AUTO_INCREMENT=135167 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `place_category` (
    `place_category_id` int(11) NOT NULL AUTO_INCREMENT, 
    `place_category_place_id` int(11) NOT NULL DEFAULT '0', 
    `place_category_category_id` int(11) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`place_category_id`), 
    UNIQUE KEY `place_category_place_id` (`place_category_place_id`,`place_category_category_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=208987 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `category` (
    `category_id` int(11) NOT NULL AUTO_INCREMENT, 
    `category_name` varchar(255) DEFAULT NULL, 
    PRIMARY KEY (`category_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=168 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `review` (
    `review_id` int(11) NOT NULL AUTO_INCREMENT, 
    `review_user_id` int(11) NOT NULL DEFAULT '0', 
    `review_place_id` int(11) NOT NULL DEFAULT '0', 
    `review_map_item_id` int(11) NOT NULL DEFAULT '0', 
    `review_otm_item_name` varchar(156) DEFAULT NULL, 
    `review_headline` varchar(255) DEFAULT NULL, 
    `review_message` text, 
    `review_rating` tinyint(1) NOT NULL DEFAULT '0', 
    `review_datetime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, 
    `review_edited_datetime` datetime DEFAULT NULL, 
    `review_hidden` tinyint(1) NOT NULL DEFAULT '0', 
    `review_deleted` tinyint(1) NOT NULL DEFAULT '0', 
    `review_status` set('pending','published','hidden','deleted') NOT NULL, 
    PRIMARY KEY (`review_id`), 
    KEY `review_map_item_id` (`review_map_item_id`), 
    KEY `review_place_id` (`review_place_id`), 
    KEY `review_user_id` (`review_user_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `map_price` (
    `map_price_id` int(11) NOT NULL AUTO_INCREMENT, 
    `map_price_item_id` int(11) NOT NULL DEFAULT '0', 
    `map_price_label` varchar(50) DEFAULT NULL, 
    `map_price_value` decimal(10,2) DEFAULT NULL, 
    PRIMARY KEY (`map_price_id`), 
    KEY `map_price_item_id` (`map_price_item_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=5872 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 

CREATE TABLE `county_list` (
    `county_id` int(11) NOT NULL AUTO_INCREMENT, 
    `county_country_id` int(11) NOT NULL DEFAULT '0', 
    `county_name` varchar(120) DEFAULT NULL, 
    `county_alias` varchar(120) DEFAULT NULL, 
    PRIMARY KEY (`county_id`), 
    KEY `county_alias` (`county_alias`), 
    KEY `county_country_id` (`county_country_id`) 
) ENGINE=InnoDB AUTO_INCREMENT=142 DEFAULT CHARSET=latin1 ROW_FORMAT=COMPACT 
+0

インデックスはありますか? –

+0

IDフィールドのデータ型としてINTを使用していることを確認し、それらの外部キーにインデックスを作成してください。 – Lamar

+0

申し訳ありませんが、私は元の投稿に言及すべきでした。すべての結合は、索引付きフィールドで結合されます。この問合せで使用される表には、不要な索引はありません。 – Ryan

答えて

2

ルック:

LEFT map_section_item_item_id = map_item_id

ON map_section_itemを登録しよう| 1 |シンプル| map_section_item |インデックス| NULL | | map_section_item_section_id | 8 | NULL | 5330 |どこで使用するか。インデックスの使用。結合バッファ(ブロック入れ子ループ)の使用| |

通知 "5330"。つまり、必要な行を見つけるために約5330項目を検索しなければならなかったということです。

単純なINDEX(map_section_item_item_id)では、必要な1行(または少数の行)に直接移動します。これにより、クエリの実行速度が大幅に向上します。少なくとも "行"> 1.

なぜLEFTとのそれらのための相互JOINについて

を繰り返し、?各「正しい」テーブルにはデータが欠落していますか?

問題点:すべてにプレフィックスとしてテーブル名を付けないでください。それはあまりにも混乱です。

+0

なぜ私はそれらを逃したのか分かりませんでしたこれはうまくいきました。私は最初のインデックス 'map_section_item_item_id'を追加しました。これは9.85秒から5.71秒にクエリを取りました。 2番目の索引 'map_item_flag_item_id'は3.52になりました。 3番目のインデックス 'place_map_map_id'は1.40秒に短縮され、大きな改善点です。私はまだこれをさらに掘り下げて検討し、データベースがまだ成長する前にこれを早期に初期段階に置かなければならないでしょう。あなたがジョインで言ったことは正しいです、テーブルは必ずしもそれらにデータを持っていません。 – Ryan

+0

また、完全な元のクエリを実行したところ、それは約18秒から0.10秒にまで減少しています。 – Ryan

0

MySQLの場合は、STRAIGHT_JOIN句を使用してみてください...

SELECT STRAIGHT_JOIN map_item_name 
FROM map_item 
LEFT JOIN ... 

STRAIGHT_JOINは、私がリストアップしました順序でクエリを実行するためにMySQLを伝えます。このようにして、map_itemをプライマリテーブルとして強制的に残りのすべてをルックアップセカンダリテーブルとして強制的に実行します。

+0

STRAIGHT_JOINを使用すると、9.95sでクエリが実行されます。9.87sで実行されません。 – Ryan

+0

'FORCE INDEX'と同様に、' STRAIGHT_JOIN'が今日役立ちますが、明日は悪化します。 –

関連する問題