2

かなりの時間がかかるため、最適化を使用できるいくつかのクエリがあるため、このサイトの多くの投稿を読んだ後、スキーマを変更し、インデックスを追加/変更してクエリを適切に高速化するようにしました。ほとんどの場合、私は大きな成功を収めましたが、この特定のケースでは行き詰まり、何が間違っているのかわかりません。

約 350 万行のテーブルがあります。

select count(*) from post;
+----------+
| count(*) |
+----------+
|  3652904 |
+----------+

そして、次のように作成されます。

Create Table: CREATE TABLE `post` (
  `id` varchar(255) NOT NULL DEFAULT '',
  `page_id` bigint(20) NOT NULL DEFAULT '0',
  `post_id` bigint(20) NOT NULL DEFAULT '0',
  `type` varchar(45) CHARACTER SET latin1 NOT NULL,
  ...
  `created_time` timestamp NULL DEFAULT NULL,
  `updated_time` timestamp NULL DEFAULT NULL,
  `timestamp` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`page_id`,`post_id`),
  KEY `created_time` (`created_time`),
  KEY `target_id` (`target_id`),
  KEY `id` (`id`) USING BTREE
) ENGINE=TokuDB DEFAULT CHARSET=utf8
/*!50100 PARTITION BY HASH (page_id)
PARTITIONS 10 */

行数が非常に少なく、次のように作成される別のテーブル:

select count(*) from privacy;
+----------+
| count(*) |
+----------+
|    19093 |
+----------+

Create Table: CREATE TABLE `privacy` (
  `id` varchar(255) CHARACTER SET latin1 NOT NULL,
  `page_id` bigint(20) DEFAULT '0',
  `description` text CHARACTER SET latin1,
  `value` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
  `allow` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
  `deny` varchar(255) CHARACTER SET latin1 DEFAULT NULL,
  `json` text CHARACTER SET latin1,
  `timestamp` timestamp NULL DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `page_id` (`page_id`)
) ENGINE=TokuDB DEFAULT CHARSET=utf8

最適化しようとしている選択は次のとおりです。

explain partitions 
SELECT   
  post.id,  post.type,  privacy.description  
FROM   
  post 
LEFT JOIN privacy ON privacy.id = post.id  
WHERE post.page_id = 12854644836;
+----+-------------+---------+------------+------+---------------+---------+---------+-------+-------+-------+
| id | select_type | table   | partitions | type | possible_keys | key     | key_len | ref   | rows  | Extra |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+-------+-------+
|  1 | SIMPLE      | post    | p6         | ref  | PRIMARY       | PRIMARY | 8       | const | 34685 |       |
|  1 | SIMPLE      | privacy | NULL       | ALL  | NULL          | NULL    | NULL    | NULL  | 19093 |       |
+----+-------------+---------+------------+------+---------------+---------+---------+-------+-------+-------+

残念ながら、この選択には数分かかり、その理由がわかりません。説明で主キーが取得されないことに気付きました。これは、2 つのテーブルの文字セットの違いによるものなのだろうかと思います。それでも、Explain からはそれほど多くの行が含まれるはずがありませんが、実行にはまだ時間がかかります。

16754 rows in set (5 min 33.68 sec)

テーブルだけからの選択はかなり高速です。

select * from post where page_id = 12854644836;
16754 rows in set (0.22 sec)

select * from privacy where page_id = 12854644836;
234 rows in set (0.01 sec)

このサイトの MySQL 専門家の何人かは、私を正しい方向に向けることができますか? ありがとう :)

4

2 に答える 2

2

これは、id列が privacy テーブルで latin1 として定義され、posts テーブルで utf8 として定義されているためです。

MySQL は、結合の id 列で文字セット変換を行う必要があるため、インデックスを使用できません。文字セットを変更すると、問題が修正されます。

于 2012-07-08T00:08:00.140 に答える
0

MySQL は、単一のクエリ内で同じテーブル参照に対して複数のインデックスを使用できません。このクエリでは両方の列を検索する必要があるため、posts テーブルに複合インデックスを作成する必要があり(id,page_id)ます (1 番目は結合用、2 番目はフィルター基準用)。

于 2012-07-07T23:50:59.027 に答える