6

最適化しようとしているブラウズ カテゴリ クエリがあります。私は一時的な使用で終わります。説明でファイルソートを使用すると、たとえば60,000行のカテゴリでクエリが遅くなります。Order By 句を削除すると、クエリは非常に高速に実行され、0.05 秒で 60,000 行が処理されます。Order By 句を使用すると、約 5 秒と非常に遅くなります。Parts には、Parts_Category と同様に約 500,000 行が含まれます。

sort_index という部品 (ステータス、レベル、倉庫、更新済み) のグループ インデックスがあります。

私が持っている説明の上部に | すべて | 一時的な使用; ファイルソートの使用

他のすべてのインデックスは正常に表示されています。誰かが私に何が問題なのか教えてもらえますか? 私はアイデアがありません。おそらくパフォーマンスを向上させるために、このクエリを再配置する必要がありますか?

クエリ。

SELECT Parts.*, Image.type, Image.width, Image.height,
(SELECT name FROM Location_State WHERE id = Parts.state_id) AS state, 
(SELECT name FROM Location_Region WHERE id = Parts.region_id) AS region, 
(SELECT start_date FROM Promotion WHERE id = Parts.promotion_id) AS promotion_start_date, 
(SELECT end_date FROM Promotion WHERE id = Parts.promotion_id) AS promotion_end_date 
FROM ( SELECT parts_id FROM Parts_Category WHERE Parts_Category.category_id = '40' 
UNION SELECT parts_id FROM Parts_Category WHERE Parts_Category.main_category_id = '40') cid 
LEFT JOIN Image ON Parts.image_id = Image.id
JOIN Parts ON Parts.id = cid.parts_id AND Parts.status = 'A'
ORDER BY Parts.level DESC, Parts.warehouse DESC, Parts.updated DESC LIMIT 0, 15
テーブル部品のテーブル構造

フィールド タイプ Null デフォルト
id int(11) いいえ auto_increment
image_id int(11) はい 0
gallery_id int(11) はい 0
image_count int(3) はい 0
プロモーション ID int(11) はい 0
country_id int(11) はい NULL
state_id int(11) はい NULL
region_id int(11) はい NULL
city_id int(11) はい NULL
area_id int(11) はい NULL
更新日時 はい 0000-00-00 00:00:00
入力日時 はい 0000-00-00 00:00:00
更新日 日付 はい 0000-00-00
discount_id varchar(10) はい NULL
タイトル varchar(100) はい
search_title varchar(255) はい
倉庫 varchar(50) はい
url varchar(255) はい
display_url varchar(255) はい
Friendly_url varchar(100) はい NULL
description varchar(255) はい
キーワード varchar(1000) はい NULL
attachment_file varchar(255) はい
attachment_caption varchar(255) はい
status char(1) はい
レベル tinyint(3) はい 0
世界的 tinyint(1) はい 0
random_number int(11) はい NULL
リマインダー tinyint(4) はい NULL
category_search varchar(1000) はい
video_snippet varchar(1000) はい
importID int(11) はい 0

インデックス

プライマリ 518623 ID
乱数 INDEX 32201 乱数
country_id インデックス 1 country_id
state_id INDEX 8 状態_id
region_id インデックス 5 region_id
更新日 INDEX 1 更新日
全世界 INDEX 1 全世界
フレンドリーな URL インデックス 518623 フレンドリーな URL
プロモーション ID INDEX 1 プロモーション ID
city_id インデックス 1 city_id
エリアID INDEX 1 エリアID
zip_code インデックス 2790 zip_code
importID INDEX 518623 importID
image_id インデックス 10 image_id

--------------
index_browse_category INDEX 52
レベル
状態
倉庫   
更新しました
-----------------
キーワード FULLTEXT 1
説明
キーワード
カテゴリ検索


パーツ_カテゴリ

id int(11) いいえ auto_increment     
parts_id int(11) いいえ 0       
category_id int(11) いいえ 0       
main_category_id int(10) いいえ 0   

索引

プライマリ プライマリ 519330 id
カテゴリ ID INDEX 519330 カテゴリ ID
parts_id
main_category_id INDEX 519330 main_category_id
parts_id





4

2 に答える 2

42

クエリを次のように書き直してみてください。

SELECT  p.*, i.type, i.width, i.height,
        (SELECT name FROM Location_State WHERE id = p.state_id) AS state, 
        (SELECT name FROM Location_Region WHERE id = p.region_id) AS region, 
        (SELECT start_date FROM Promotion WHERE id = p.promotion_id) AS promotion_start_date, 
        (SELECT end_date FROM Promotion WHERE id = p.promotion_id) AS promotion_end_date 
FROM    parts p
LEFT JOIN
        image i
ON      i.id = p.image_id
WHERE   EXISTS (
        SELECT  NULL
        FROM    Parts_Category pc
        WHERE   pc.category_id = '40'
                AND pc.parts_id = p.id
        UNION ALL
        SELECT  NULL
        FROM    Parts_Category pc
        WHERE   pc.main_category_id = '40'
                AND pc.parts_id = p.id
        )
        AND p.status = 'A'
ORDER BY
        p.status DESC, p.level DESC, p.warehouse DESC, p.updated DESC
LIMIT   15

これが効率的に機能するには、次のインデックスが必要です。

parts (status, level, warehouse, updated) -- this one you have
parts_category (category_id, parts_id)
parts_category (main_category_id, parts_id)

アップデート:

次のようにテーブルを作成しました。

DROP TABLE IF EXISTS `test`.`image`;
CREATE TABLE  `test`.`image` (
  `id` int(11) NOT NULL,
  `type` int(11) NOT NULL,
  `width` int(11) NOT NULL,
  `height` int(11) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `test`.`location_region`;
CREATE TABLE  `test`.`location_region` (
  `id` int(11) NOT NULL,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `test`.`location_state`;
CREATE TABLE  `test`.`location_state` (
  `id` int(11) NOT NULL,
  `name` varchar(20) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `test`.`parts`;
CREATE TABLE  `test`.`parts` (
  `id` int(11) NOT NULL,
  `status` char(1) NOT NULL,
  `level` int(11) NOT NULL,
  `warehouse` int(11) NOT NULL,
  `updated` int(11) NOT NULL,
  `state_id` int(11) NOT NULL,
  `region_id` int(11) NOT NULL,
  `promotion_id` int(11) NOT NULL,
  `image_id` int(11) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`),
  KEY `status` (`status`,`level`,`warehouse`,`updated`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `test`.`parts_category`;
CREATE TABLE  `test`.`parts_category` (
  `id` int(11) NOT NULL,
  `parts_id` int(11) NOT NULL,
  `category_id` int(11) NOT NULL,
  `main_category_id` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `ix_pc_cat_parts` (`category_id`,`parts_id`),
  KEY `ix_pc_main_parts` (`main_category_id`,`parts_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `test`.`promotion`;
CREATE TABLE  `test`.`promotion` (
  `id` int(11) NOT NULL,
  `start_date` datetime NOT NULL,
  `end_date` datetime NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

そしてそれらにサンプルデータを入力しました:

INSERT
INTO    parts
SELECT  id,
        CASE WHEN RAND() < 0.1 THEN 'A' ELSE 'B' END,
        RAND() * 100,
        RAND() * 100,
        RAND() * 100,
        RAND() * 50,
        RAND() * 50,
        RAND() * 50,
        RAND() * 50
FROM    t_source
LIMIT 500000;
INSERT
INTO    parts_category
SELECT  id,
        id,
        RAND() * 100,
        RAND() * 100
FROM    t_source
LIMIT 500000;
INSERT
INTO    location_state
SELECT  id, CONCAT('State ', id)
FROM    t_source
LIMIT 1000;
INSERT
INTO    location_region
SELECT  id, CONCAT('Region ', id)
FROM    t_source
LIMIT 1000;
INSERT
INTO    promotion
SELECT  id,
        '2009-07-22' - INTERVAL RAND() * 5 - 20 DAY,
        '2009-07-22' - INTERVAL RAND() * 5 DAY
FROM    t_source
LIMIT 1000;

上記のクエリを実行する30 millisecondsと、次のプランが生成されます。

1, 'PRIMARY', 'p', 'ref', 'status', 'status', '3', 'const', 107408, 'Using where'
1, 'PRIMARY', 'i', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'test.p.image_id', 1, ''
6, 'DEPENDENT SUBQUERY', 'pc', 'ref', 'ix_pc_cat_parts', 'ix_pc_cat_parts', '8', 'const,test.p.id', 1, 'Using index'
7, 'DEPENDENT UNION', 'pc', 'ref', 'ix_pc_main_parts', 'ix_pc_main_parts', '8', 'const,test.p.id', 1, 'Using index'
, 'UNION RESULT', '<union6,7>', 'ALL', '', '', '', '', , ''
5, 'DEPENDENT SUBQUERY', 'Promotion', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'test.p.promotion_id', 1, ''
4, 'DEPENDENT SUBQUERY', 'Promotion', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'test.p.promotion_id', 1, ''
3, 'DEPENDENT SUBQUERY', 'Location_Region', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'test.p.region_id', 1, ''
2, 'DEPENDENT SUBQUERY', 'Location_State', 'eq_ref', 'PRIMARY', 'PRIMARY', '4', 'test.p.state_id', 1, ''

ご覧のとおり、いいえtemporary、いいえfilesort、すべてが非常に高速です。

もうあなたを助けるために、あなたのテーブルがどのように定義されているかを確認する必要があります.

于 2009-07-22T15:04:45.817 に答える