Какое разумное количество строк и таблиц можно объединить в MySQL? - PullRequest
1 голос
/ 03 апреля 2010

У меня есть одна таблица, которая отображает местоположения в почтовые индексы. Например, штат Нью-Йорк имеет около 2000 почтовых индексов. У меня есть другая таблица, которая сопоставляет почту с почтовыми кодами, на которые она была отправлена, но в этой таблице около 5 миллионов строк. Я хочу найти всю почту, которая была отправлена ​​в штат Нью-Йорк, которая кажется достаточно простой, но запрос невероятно медленный. Я не мог даже ждать достаточно долго, чтобы это закончилось. Проблема в том, что там 5 миллионов строк? Я не могу не думать, что 5 миллионов не должно быть таким большим числом для компьютера в эти дни ... О, и все проиндексировано. Разве 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 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           | 
+----+-------------+-------+--------+--------------------------------------------------------+---------+---------+----------------------+---------+---------------------------------+

Ответы [ 2 ]

5 голосов
/ 03 апреля 2010

MySQL отлично способен обрабатывать объединения, включающие 5 миллионов строк или даже намного больше, чем это.

Ваша проблема, вероятно, одна из двух:

  • Вам не хватает индекса.
  • Вы пишете свой запрос таким образом, что оптимизатор не может использовать лучший индекс, например, если вы используете функции, которые не sargable для вашего проиндексированного столбца в условии соединения. 1010 *

Поскольку вы утверждаете, что «все проиндексировано», я думаю, что это второе. Опубликуйте информацию о вашей таблице и ваш запрос, и мы сможем помочь вам ее исправить.

Вы также можете запустить EXPLAIN для вашего запроса, чтобы увидеть, какие индексы он использует.

0 голосов
/ 03 апреля 2010

Вы должны иметь возможность объединить 10 таблиц с самыми большими таблицами, имеющими строки в несколько миллионов и более, и вы сможете быстро получить результаты.

Предположим, что что-то не так со стратегией индексирования, операцией запроса или планом запроса.

Это не имеет ничего общего с SQL как таковым; это может быть связано с MySQL или конкретным механизмом хранения, который вы используете в MySQL.

Знаете ли вы, что стандарт SQL не определяет ничего, связанного с индексами? Можно утверждать, что все, что связано с индексами, является нестандартным, хотя «дополнительный к стандартному» может быть лучшим способом посмотреть на это.

...