Проблема производительности запроса

0

У меня возникают проблемы с определенной производительностью запросов, у меня есть следующие 2 таблицы:

CREATE TABLE `customers` (
  `CustFullName` varchar(45) NOT NULL,
  `CustPassword` varchar(45) NOT NULL,
  `CustEmail` varchar(128) NOT NULL,
  `SocialNetworkId` tinyint(4) NOT NULL,
  `CustUID` varchar(64) CHARACTER SET ascii NOT NULL,
  `CustMoney` bigint(20) NOT NULL DEFAULT '0',
  `LastIpAddress` varchar(45) CHARACTER SET ascii NOT NULL,
  `LastLoginTime` datetime NOT NULL DEFAULT '1900-10-10 10:10:10',
  `SmallPicURL` varchar(120) CHARACTER SET ascii DEFAULT '',
  `LargePicURL` varchar(120) CHARACTER SET ascii DEFAULT '',
  `LuckyChips` int(10) unsigned NOT NULL DEFAULT '0',
  `AccountCreationTime` datetime NOT NULL DEFAULT '2009-11-11 11:11:11',
  `AccountStatus` tinyint(4) NOT NULL DEFAULT '1',
  `CustLevel` int(11) NOT NULL DEFAULT '0',
  `City` varchar(32) NOT NULL DEFAULT '',
  `State` varchar(32) NOT NULL DEFAULT '0',
  `Country` varchar(32) NOT NULL DEFAULT '',
  `Zip` varchar(16) CHARACTER SET ascii NOT NULL,
  `CustExp` bigint(20) NOT NULL DEFAULT '0',
  PRIMARY KEY (`CustUID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

И:

CREATE TABLE `mutualfriends` (
  `CustUID` varchar(32) CHARACTER SET ascii NOT NULL,
  `CustUID2` varchar(32) CHARACTER SET ascii NOT NULL,
  `FType` tinyint(4) NOT NULL,
  PRIMARY KEY (`CustUID`,`CustUID2`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8

таблица клиентов содержит 1M строк и mutalfriends размером около 50 тыс. строк.

Мне нужны результаты следующего запроса:

SELECT c.CustUID, c.CustFullName, c.CustMoney, c.SmallPicURL
FROM `customers` c
WHERE c.`CustUID` = '9:2'
OR c.`CustUID` IN
(SELECT m.CustUID2 FROM mutualfriends m WHERE m.CustUID = '9:2');
OR c.`CustUID` IN
(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2');

по какой-то причине я не понимаю, этот запрос занимает около 10 секунд, чтобы закончить. Подзапросы содержат не более трех строк каждый, если я помещаю константы вместо:

(SELECT m.CustUID2 FROM mutualfriends m WHERE m.CustUID = '9:2');

И:

 (SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2');

Например:

 SELECT c.CustUID, c.CustFullName, c.CustMoney, c.SmallPicURL
    FROM `customers` c
    WHERE c.`CustUID` = '9:2'
    OR c.`CustUID` IN
    ('9:3','9:4','9:5');
    OR c.`CustUID` IN
    ('9:6','9:7');

Затем для завершения запроса требуется несколько мс. Что я делаю неправильно здесь, этот запрос не должен занимать больше нескольких мс...

Также я могу добавить, что эта часть запроса:

(SELECT m.CustUID2 FROM mutualfriends m WHERE m.CustUID = '9:2');
(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2');

также принимает несколько мс....

Теги:
performance

3 ответа

0

Некоторые случайные догадки:

(SELECT m.CustUID FROM mutualfriends m WHERE m.CustUID2 = '9:2');

... возможно не может эффективно использовать индекс (CustUID, CustUID2). Вы должны проверить план объяснения. Если это не так, подумайте о добавлении еще одного uniue-индекса (CustUID2, CustUID).

Выражения вроде

WHERE <constant>
   OR <subquery>

... генерирует дрянной план в Oracle. Может быть, это так и для MySQL? Его обычно можно решить, если вы как-то отредактируете константное выражение внутри подзапроса или немного перефразируете логику.

Еще одна идея - выполнить три запроса и СОЕДИНИТЬ их вместе. Если вы ожидаете возвращения многих строк, этот параметр менее привлекателен, поскольку сортировка приведет к снижению производительности.

select *
  from customer 
 where CustUID = '9:2'
union
select *
  from customer
 where CustUID in(select m.CustUID from mutualfriends m where m.CustUID2 = '9:2')
union
select *
  from customer
 where CustUID in(select m.CustUID2 from mutualfriends m where m.CustUID = '9:2')
0

Посмотрите http://dev.mysql.com/doc/refman/5.0/en/using-explain.html. Также быстрый поиск Google вернется с множеством отправных точек для обработки оптимизаций SQL. Большинство полагаются только на EXPLAIN, поэтому начните там.

Что касается вашего запроса, CustUID2 вызовет полное сканирование таблицы, поскольку оно не будет индексироваться напрямую. Кроме того, будьте осторожны с использованием подзапросов, так как я встречал некоторые случаи, когда оптимизатор не мог полностью оптимизировать подзапрос... в моем случае этого было достаточно, чтобы разделить запрос на большее количество запросов (без подзапросов), Это также может помочь использовать JOIN, поскольку они обрабатываются иначе, чем подзапросы.

0

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

  • 0
    Я так не думаю, потому что одна эта строка занимает несколько мс: (ВЫБЕРИТЕ m.CustUID2 ОТ взаимных друзей m ГДЕ m.CustUID = '9: 2');

Ещё вопросы

Сообщество Overcoder
Наверх
Меню