1

場所を郵便番号にマップするテーブルが 1 つあります。たとえば、ニューヨーク州には約 2000 の郵便番号があります。メールを送信先の郵便番号にマップする別のテーブルがありますが、このテーブルには約 500 万行あります。ニューヨーク州に送信されたすべてのメールを検索したいのですが、これは簡単に思えますが、クエリは信じられないほど遅いです。私はそれが終わるのを十分に長く待つことさえできませんでした. 500万行あるのが問題?最近のコンピューターにとって、500 万はそれほど大きな数ではないと思わずにはいられません...ああ、すべてがインデックス化されています。SQL は、このような大規模な結合を処理するように設計されていないのでしょうか?

更新: 人々が尋ねたように、私が使用しているテーブル定義とクエリでこの質問を更新しました。

-- Roughly 70,000 rows
CREATE TABLE `mail_zip` (
  `mail_id` int(11) default NULL,
  `zip` int(11) default NULL,
  KEY `index_mail_zip_on_mail_id` (`mail_id`),
  KEY `index_mail_zip_on_zip` (`zip`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

-- Roughly 5,000,000 rows
CREATE TABLE `geographies` (
  `city_id` int(11) default NULL,
  `postal_code` int(11) default NULL,
  KEY `index_geographies_on_city_id` (`city_id`),
  KEY `index_geographies_on_postal_code` (`postal_code`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1

-- Query
select mz.mail_id from mail_zip mz join geographies g on mz.zip = g.postal_code where g.city_id = 36 limit 10;

更新 2: わかりました、私は嘘をつきました。適切なインデックスを使用すると、上記のクエリは正常に機能します。問題は、実際には order by 句です。以下の 2 つのほぼ同一のクエリを参照してください。唯一の違いは、"order by m.sent_on desc" であり、クエリに 4 分 30 秒余分に追加されます。また、説明を使用して、注文を追加すると、ファイルソートが使用されますが、これが速度を低下させているに違いありません。しかし、sent_on はインデックス化されているのに、なぜインデックスを使用しないのでしょうか? インデックスをきちんと作っていないに違いない。

-- Roughly 350,000 rows
CREATE TABLE `mail` (
  `id` int(11) NOT NULL auto_increment,
  `sent_on` datetime default NULL,
  `title` varchar(255) default NULL,
  PRIMARY KEY  (`id`),
  KEY `index_mail_on_sent_on` (`sent_on`),
) ENGINE=InnoDB DEFAULT CHARSET=latin1

-- Runs in 0.19 seconds
-- Query
select distinct(m.id), m.title from mail m join mail_zip mz on mz.mail_id = m.id join geographies g on g.postal_code = mz.zip where g.city_id = 36 limit 10;

+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+-----------------------+
| id | select_type | table | type   | possible_keys                                          | key     | key_len | ref                  | rows    | Extra                 |
+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+-----------------------+
|  1 | SIMPLE      | mz    | ALL    | index_mail_zip_on_com_id,index_mail_zip_on_zip         | NULL    | NULL    | NULL                 | 5260053 | Using temporary       | 
|  1 | SIMPLE      | m     | eq_ref | PRIMARY                                                | PRIMARY | 4       |            mz.com_id |       1 |                       | 
|  1 | SIMPLE      | g     | ref    | index_geographies_on_city_id,zip                       | zip     | 5       |            mz.zip    |       1 | Using where; Distinct | 
+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+-----------------------+

-- Runs in 4 minutes and 30 seconds
-- Query
select distinct(m.id), m.title from mail m join mail_zip mz on mz.mail_id = m.id join geographies g on g.postal_code = mz.zip where g.city_id = 36 order by m.sent_on desc limit 10;

+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+---------------------------------+
| id | select_type | table | type   | possible_keys                                          | key     | key_len | ref                  | rows    | Extra                           |
+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+---------------------------------+
|  1 | SIMPLE      | mz    | ALL    | index_mail_zip_on_com_id,index_mail_zip_on_zip         | NULL    | NULL    | NULL                 | 5260053 | Using temporary; Using filesort | 
|  1 | SIMPLE      | m     | eq_ref | PRIMARY                                                | PRIMARY | 4       |            mz.com_id |       1 |                                 | 
|  1 | SIMPLE      | g     | ref    | index_geographies_on_city_id,zip                       | zip     | 5       |            mz.zip    |       1 | Using where; Distinct           | 
+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+---------------------------------+
4

2 に答える 2

5

MySQL は、500 万行またはそれ以上の行を含む結合を完全に処理できます。

あなたの問題は、おそらく次の2つのいずれかです。

「すべてがインデックス化されている」と主張しているので、2番目だと思います。テーブル情報とクエリを投稿してください。修正をお手伝いできるはずです。

クエリで EXPLAIN を実行して、使用しているインデックスを確認することもできます。

于 2010-04-02T21:28:44.760 に答える
0

議論のために、数百万以上の行を持つ最大のテーブルを持つ10個のテーブルを結合できるはずであり、結果をすばやく取得できるはずです。

インデックス作成戦略、クエリ操作、またはクエリ プランに問題があるとします。

SQL 自体とは何の関係もありません。MySQL、または MySQL で使用している特定のストレージ エンジンに関連している可能性があります。

SQL 標準では、インデックスに関連するものは何も定義されていないことをご存知ですか? インデックスに関連するものはすべて非標準であると主張することもできますが、「標準に追加」という方が適切な見方かもしれません。

于 2010-04-02T21:34:16.237 に答える