Какие варианты у меня есть, чтобы сделать мой заказ быстрее? - PullRequest
1 голос
/ 22 января 2009

У меня следующий запрос:

SELECT DISTINCT c.id
FROM clients AS c
LEFT JOIN client_project AS cp ON (cp.client_id = c.id)
WHERE cp.project_id = 1
    AND c.active_flag = 1
ORDER BY c.client_name

Если я уберу заказ на, запрос займет 0,005 секунды. При заказе по запросу запрос занимает 1,8-1,9 секунды. У меня есть индекс на client_name.

Что еще могло бы улучшить скорость?

Редактировать: c.id является первичным ключом, но для него может быть несколько записей в client_project, и поэтому это может привести к более чем одной записи для каждого идентификатора. Кроме того, удаление отличительного составляет 0,1 секунды разницы в запросе.

Дополнение: Вот таблица моих клиентов:

CREATE TABLE IF NOT EXISTS `clients` (
  `id` int(11) NOT NULL auto_increment,
...
  `organization` varchar(255) character set utf8 collate utf8_bin NOT NULL,
  `client_name` varchar(255) character set utf8 collate utf8_bin NOT NULL,
  `active_flag` tinyint(1) NOT NULL,
...
  PRIMARY KEY  (`id`),
  KEY `active_flag` (`active_flag`),
...
  KEY `organization` (`organization`),
  KEY `client_name` (`client_name`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;

Использование MySQL 5.0

Ответы [ 9 ]

2 голосов
/ 22 января 2009

смотрит на ваши правки

попробуйте использовать EXISTS в этом случае

SELECT  c.id
FROM clients AS c
WHERE EXISTS (SELECT * FROM  client_project AS cp  
              WHERE cp.client_id = c.id and cp.project_id = 1)
AND c.active_flag = 1
2 голосов
/ 22 января 2009

Попробуйте добавить этот ключ к client_projects:

KEY(client_name, id, active_flag)
1 голос
/ 19 февраля 2009

У меня нет решения для вас, но у меня есть объяснение.

MySQL использует только один индекс для таблицы. У вас есть две таблицы, и индексы, используемые в них, являются первичным ключом одной (WHERE cp.project_id = 1), и соединение заставляет использовать индекс второй таблицы для эффективного объединения.

Использование ORDER BY после этого для MySQL становится невозможным использовать индекс для упорядочения. Добавление большего количества индексов не поможет. EXPLAIN покажет вам, какие индексы выбрал MySQL для каждой таблицы. Формирование индекса приведет к замедлению работы других частей запроса.

1 голос
/ 22 января 2009

Вероятно, есть индексы на clients.id и clients.active_flag, поэтому оптимизатору не нужно переходить к полной таблице (или к дополнительному индексу), если вы не хотите сортировать ее.

Проверьте план оптимизатора, я думаю, что в MySQL это объясняют.

Индекс на client_name, id может помочь (или не может - проверить план).

Пара дополнительных вопросов / идей / замечаний, которые могут помочь ...

  • Зачем заказывать по имени, если все, что вы получаете от выбора, это идентификатор
  • Зачем выполнять левое соединение, если у вас есть условие where "cp.project_id", поэтому клиенты без проекта не будут возвращены в любом случае
  • Что касается других постеров (paul, eppz), то для клиентов с более чем одним проектом может потребоваться «отдельный». Так что другая идея - сделать что-то вроде

    выберите идентификатор от клиентов c где существует (выберите * из cp клиента_проекта, где c.id = cp.client_id)

0 голосов
/ 18 февраля 2009

Вам нужно будет принудительно использовать индекс на client_name:

SELECT id
FROM (
  SELECT c.id,
    (
    SELECT 1
    FROM client_projects cp
    WHERE cp.client_id = c.id
      AND cp.project_id = 1
    LIMIT 1
    ) e
FROM clients c
FORCE INDEX (client_name)
WHERE c.active_flag = 1
ORDER BY
  client_name
) co
WHERE e IS NOT NULL
0 голосов
/ 22 января 2009

Некоторые оптимизации являются независимыми от поставщика БД, в то время как другие зависят от поставщика БД. Вот пара вещей, чтобы попробовать.

  • Удалите DISTINCT, как предлагается в другом месте.
  • Рассмотрите возможность использования внутреннего соединения. Я понимаю, что это не может быть жизнеспособным вариантом в вашей ситуации.

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

0 голосов
/ 22 января 2009

почему вы заказываете по имени клиента, если даже не возвращаете его?

Тебе тоже нужно отличное?

Почему вы делаете левое соединение, если ваше предложение where все равно сделает его внутренним соединением

Имея этот WHERE cp.project_id = 1 вместо AND cp.project_id = 1 перед предложением WHERE, в любом случае это ВНУТРЕННЕЕ СОЕДИНЕНИЕ

0 голосов
/ 22 января 2009

Является ли c.id первичным ключом? Если это так, вы не должны делать DISTINCT для него, потому что он уже различен, и форсирование DISTINCT может привести к его сортировке по id, а затем сортировке по client_name.

0 голосов
/ 22 января 2009

Является ли c.id столбцом идентификации? Если это так, я не думаю, что вам понадобится DISTINCT, поскольку каждый c.id будет уникальным.

EDIT

Таким образом, c.id может иметь несколько записей в cp, даже если cp.project_id = 1?

EDIT

Просто любопытно, почему вы хотите сделать заказ по имени клиента, когда вы его не выбираете.

...