2

テーブル定義とクエリの説明:

アイテム |

CREATE TABLE `item` ( 
`item_id` int(11) NOT NULL AUTO_INCREMENT, 
`item_type_id` int(11) NOT NULL, 
`brand_id` int(11) NOT NULL, 
`site_id` int(11) NOT NULL, 
`seller_id` int(11) NOT NULL, 
`title` varchar(175) NOT NULL, 
`desc` text NOT NULL, 
`url` varchar(767) NOT NULL, 
`price` int(11) NOT NULL, 
`photo` varchar(255) NOT NULL, 
`photo_file` varchar(255) NOT NULL, 
`photo_type` varchar(32) NOT NULL, 
`has_photo` enum('yes','no','pending') NOT NULL DEFAULT 'pending', 
`added_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
`updated_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
`created_at` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
`normalized_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
`location` varchar(128) NOT NULL, 
PRIMARY KEY (`item_id`), 
KEY `item_type_id` (`item_type_id`), 
KEY `brand_id` (`brand_id`), 
KEY `site_id` (`site_id`), 
KEY `seller_id` (`seller_id`), 
KEY `created_at` (`created_at`), 
KEY `added_at` (`added_at`), 
KEY `normalized_time` (`normalized_time`), 
KEY `typephototime` (`item_type_id`,`has_photo`,`normalized_time`), 
KEY `brandidphoto` (`brand_id`,`item_type_id`,`has_photo`), 
KEY `brandidphoto2` (`brand_id`,`item_type_id`,`has_photo`), 
KEY `idphoto` (`item_type_id`,`has_photo`), 
KEY `idphototime` (`item_type_id`,`has_photo`,`normalized_time`), 
KEY `idphoto2` (`item_type_id`,`has_photo`), 
KEY `typepricebrandid` (`item_type_id`,`price`,`brand_id`,`item_id`), 
KEY `sellertypephototime` (`seller_id`,`item_type_id`,`has_photo`,`normalized_time`), 
KEY `typephoto` (`item_type_id`,`has_photo`) 
) ENGINE=MyISAM AUTO_INCREMENT=508885 DEFAULT CHARSET=latin1 | 

mysql> 説明 SELECT item.* FROM itemWHERE item.item_type_id = "1" AND item.has_photo = "yes" ORDER BY normalized_time DESC LIMIT 1;

+----+-------------+-------+------+------------------------------------------------------------------------------------+---------------+---------+-------------+-------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
+----+-------------+-------+------+------------------------------------------------------------------------------------+---------------+---------+-------------+-------+-------------+ 
| 1 | SIMPLE | item | ref | item_type_id,typephototime,idphoto,idphototime,idphoto2,typepricebrandid,typephoto | typephototime | 5 | const,const | 69528 | Using where | 
+----+-------------+-------+------+------------------------------------------------------------------------------------+---------------+---------+-------------+-------+-------------+ 
1 row in set (0.02 sec) 

mysql> 説明 SELECT * FROM itemWHERE item_type_id = "1" AND (price BETWEEN "25" AND "275") AND brand_id = "10" ORDER BY item_id DESC LIMIT 1;

+----+-------------+-------+-------+------------------------------------------------------------------------------------------------------------------------+---------+---------+------+------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
+----+-------------+-------+-------+------------------------------------------------------------------------------------------------------------------------+---------+---------+------+------+-------------+ 
| 1 | SIMPLE | item | index | item_type_id,brand_id,typephototime,brandidphoto,brandidphoto2,idphoto,idphototime,idphoto2,typepricebrandid,typephoto | PRIMARY | 4 | NULL | 203 | Using where | 
+----+-------------+-------+-------+------------------------------------------------------------------------------------------------------------------------+---------+---------+------+------+-------------+ 
1 row in set (0.01 sec) 

mysql> 説明 SELECT item.* FROM itemWHERE item.brand_id = "10" AND item.item_type_id = "1" AND item.has_photo = "yes" ORDER BY normalized_time DESC LIMIT 1;

+----+-------------+-------+-------+------------------------------------------------------------------------------------------------------------------------+-----------------+---------+------+--------+-------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
+----+-------------+-------+-------+------------------------------------------------------------------------------------------------------------------------+-----------------+---------+------+--------+-------------+ 
| 1 | SIMPLE | item | index | item_type_id,brand_id,typephototime,brandidphoto,brandidphoto2,idphoto,idphototime,idphoto2,typepricebrandid,typephoto | normalized_time | 8 | NULL | 502397 | Using where | 
+----+-------------+-------+-------+------------------------------------------------------------------------------------------------------------------------+-----------------+---------+------+--------+-------------+ 
1 row in set (2.15 sec) 

mysql> 説明 SELECT COUNT(*) FROM itemWHERE item.item_type_id = "1" AND item.has_photo = "yes" ;

+----+-------------+-------+------+------------------------------------------------------------------------------------+-----------+---------+-------------+-------+--------------------------+ 
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra | 
+----+-------------+-------+------+------------------------------------------------------------------------------------+-----------+---------+-------------+-------+--------------------------+ 
| 1 | SIMPLE | item | ref | item_type_id,typephototime,idphoto,idphototime,idphoto2,typepricebrandid,typephoto | typephoto | 5 | const,const | 71135 | Using where; Using index | 
+----+-------------+-------+------+------------------------------------------------------------------------------------+-----------+---------+-------------+-------+--------------------------+ 
1 row in set (0.01 sec)
4

2 に答える 2

1

次のインデックスは、別のインデックスの左側の列と一致するため冗長です。ほとんどの場合、これらのインデックスを削除して、スペースとオーバーヘッドを節約できます。

KEY `item_type_id` (`item_type_id`), /* redundant */
KEY `brand_id` (`brand_id`), /* redundant */
KEY `seller_id` (`seller_id`), /* redundant */
KEY `idphototime` (`item_type_id`,`has_photo`,`normalized_time`),  /* redundant */
KEY `brandidphoto2` (`brand_id`,`item_type_id`,`has_photo`), /* redundant */
KEY `idphoto` (`item_type_id`,`has_photo`), /* redundant  */
KEY `idphoto2` (`item_type_id`,`has_photo`), /* redundant */
KEY `typephoto` (`item_type_id`,`has_photo`) /* redundant */

これにより、次のインデックスが残ります。

KEY `site_id` (`site_id`), 
KEY `created_at` (`created_at`), 
KEY `added_at` (`added_at`), 
KEY `normalized_time` (`normalized_time`), 
KEY `brandidphoto` (`brand_id`,`item_type_id`,`has_photo`), 
KEY `typephototime` (`item_type_id`,`has_photo`,`normalized_time`),
KEY `typepricebrandid` (`item_type_id`,`price`,`brand_id`,`item_id`), 
KEY `sellertypephototime` (`seller_id`,`item_type_id`,`has_photo`,`normalized_time`), 

pt-duplicate-key-checkerなどのツールを使用して、冗長なインデックスを見つけることもできます。

次に、ストレージ エンジンについて考えます。

) ENGINE=MyISAM AUTO_INCREMENT=508885 DEFAULT CHARSET=latin1;

ほとんどの場合、InnoDB は MyISAM よりも優れた選択肢です。パフォーマンスだけでなく、データの完全性とクラッシュの安全性のためにも。InnoDB は 2010 年以来、デフォルトのストレージ エンジンであり、積極的に改善されている唯一のストレージ エンジンです。このテーブルのコピーを作成し、ストレージ エンジンを InnoDB に変更して、クエリに対するパフォーマンスを比較することをお勧めします。

次に、クエリのインデックスについて考えてみましょう。

SELECT item.* FROM `item` WHERE item.item_type_id = "1" AND item.has_photo = "yes" 
ORDER BY normalized_time DESC LIMIT 1; 

上のインデックスを選択する(item_type_id, has_photo, normalized_time)と、それが現在使用しているインデックスであり、typephototime.

これをさらに最適化する 1 つの方法は、インデックス内の列のみをフェッチすることです。そのとき、EXPLAIN プランに「Using index」と表示され、パフォーマンスが大幅に向上する可能性があります。

もう 1 つの重要な要素は、インデックスがメモリにキャッシュされていることを確認することkey_buffer_sizeです。MyISAM を使用する場合、またはinnodb_buffer_pool_sizeInnoDB を使用する場合は、メモリに残したいすべてのインデックスと同じ大きさになるように増やしてください。バッファよりも大きなインデックスをスキャンする必要があるクエリを実行したくないためです。それは多くのスワッピングを引き起こします。

SELECT * FROM `item` WHERE item_type_id = "1" AND (price BETWEEN "25" AND "275") AND brand_id = "10" 
ORDER BY item_id DESC LIMIT 1; 

のインデックスを選択します(item_type_id, brand_id, price)が、このクエリは現在 PRIMARY インデックスを使用しています。新しいインデックスを作成する必要があります。

SELECT item.* FROM `item` WHERE item.brand_id = "10" AND item.item_type_id = "1" AND item.has_photo = "yes" 
ORDER BY normalized_time DESC LIMIT 1; 

のインデックスを選択します(item_type_id, brand_id, has_photo, normalized_time)。新しいインデックスを作成する必要があります。

SELECT COUNT(*) FROM `item` WHERE item.item_type_id = "1" AND item.has_photo = "yes" ; 

上のインデックスを選択する(item_type_id, has_photo)と、それが現在使用しているインデックスであり、typephoto. また、「インデックスの使用」の最適化も取得しているため、他の唯一の改善点は、インデックスをメモリに保持するのに十分なバッファーがあることを確認することです。

SELECT COUNT(*)当然、多くの行をスキャンする必要があるため、クエリ を最適化するのは困難です。

COUNT(*) を最適化するもう 1 つの戦略は、カウントをオフラインで計算し、サマリー テーブルまたは memcached などのメモリ内キャッシュに保存することです。これにより、誰かがページを読み込むたびにカウントを再計算する必要がなくなります。itemただし、これは、誰かがテーブルの行を追加または削除するたびにカウントを更新する必要があることを意味し、その頻度によってはコストが高くなる可能性があります。

于 2013-07-20T18:59:20.373 に答える
0

変更することをお勧めするいくつかのこと:

  • これらすべてのインデックスは必要ありません。外部キー フィールドなど、頻繁にアクセスされるフィールドのインデックスのみが必要です。ID フィールドのインデックスを除くすべてのインデックスを削除します。
  • 実際のデータがない限り、日付を null として保存する必要があります。
  • enum データ型を避け、各値を表すフラグで smallint を使用します。例: 0 保留、1 はい、2 いいえ。

データベースのサイズを縮小するだけでなく、物事がよりクリーンになります。新しいテーブル構造は次のようになります。

CREATE TABLE `item` ( 
    `item_id` int(11) NOT NULL AUTO_INCREMENT, 
    `item_type_id` int(11) NOT NULL, 
    `brand_id` int(11) NOT NULL, 
    `site_id` int(11) NOT NULL, 
    `seller_id` int(11) NOT NULL, 
    `title` varchar(175) NOT NULL, 
    `desc` text NOT NULL, 
    `url` varchar(767) NOT NULL, 
    `price` int(11) NOT NULL, 
    `photo` varchar(255) NOT NULL, 
    `photo_file` varchar(255) NOT NULL, 
    `photo_type` varchar(32) NOT NULL, 
    `has_photo` smallint NOT NULL DEFAULT 0, 
    `added_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `updated_at` datetime NULL DEFAULT NULL, 
    `created_at` datetime NULL DEFAULT NULL, 
    `normalized_time` datetime NULL DEFAULT NULL, 
    `location` varchar(128) NULL, 
    PRIMARY KEY (`item_id`), 
    KEY `item_type_id` (`item_type_id`), 
    KEY `brand_id` (`brand_id`), 
    KEY `site_id` (`site_id`), 
    KEY `seller_id` (`seller_id`)
) ENGINE=MyISAM AUTO_INCREMENT=508885 DEFAULT CHARSET=latin1;

utf8_unicode_ciまた、照合、utf8文字セット、およびInnoDBエンジンとして使用することをお勧めします。

ただし、最初に、これらのキーをすべて削除してから、もう一度やり直してください。3 番目のクエリのエイリアシングも削除します。

SELECT * FROM item WHERE brand_id = "10" AND item_type_id = "1" AND has_photo = "yes" ORDER BY normalized_time DESC LIMIT 1;

于 2013-07-20T03:57:43.887 に答える