2015-12-04 6 views
0

Просьба предложить, как я могу ускорить выполнение этого запроса в MySQL. Он работает очень медленно.Медленная производительность запросов MySQL

Запрос:

SELECT * 
FROM product, search_attribute, search_attribute_values 
WHERE 
product.categoryid = 4800 AND product.productid = search_attribute.productid 
AND search_attribute.valueid = search_attribute_values.valueid 
GROUP BY search_attribute.valueid 

EXPLAIN запроса:

+----+-------------+-------------------------+--------+-----------------------------+---------+---------+-------------------------------------+----------+---------------------------------+ 
| id | select_type | table     | type | possible_keys    | key  | key_len | ref         | rows  | Extra       | 
+----+-------------+-------------------------+--------+-----------------------------+---------+---------+-------------------------------------+----------+---------------------------------+ 
| 1 | SIMPLE  | search_attribute  | ALL | PRIMARY,attributeid_valueid | NULL | NULL | NULL        | 79801024 | Using temporary; Using filesort | 
| 1 | SIMPLE  | search_attribute_values | eq_ref | PRIMARY      | PRIMARY | 4  | microcad.search_attribute.valueid |  1 |         | 
| 1 | SIMPLE  | product     | eq_ref | PRIMARY,product_categoryID | PRIMARY | 4  | microcad.search_attribute.productid |  1 | Using where      | 
+----+-------------+-------------------------+--------+-----------------------------+---------+---------+-------------------------------------+----------+---------------------------------+ 

Схема:

-- 
-- Table structure for table `attributenames` 
-- 

DROP TABLE IF EXISTS `attributenames`; 
/*!40101 SET @saved_cs_client  = @@character_set_client */; 
/*!40101 SET character_set_client = utf8 */; 
CREATE TABLE `attributenames` (
    `attributeid` bigint(20) NOT NULL DEFAULT '0', 
    `name` varchar(110) NOT NULL DEFAULT '', 
    `localeid` int(11) NOT NULL DEFAULT '0', 
    KEY `attributenames_attributeID` (`attributeid`), 
    KEY `attributenames_localeID` (`localeid`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 
/*!40101 SET character_set_client = @saved_cs_client */; 

-- 
-- Table structure for table `product` 
-- 

DROP TABLE IF EXISTS `product`; 
/*!40101 SET @saved_cs_client  = @@character_set_client */; 
/*!40101 SET character_set_client = utf8 */; 
CREATE TABLE `product` (
    `productid` int(11) NOT NULL DEFAULT '0', 
    `manufacturerid` int(11) NOT NULL DEFAULT '0', 
    `isactive` tinyint(1) NOT NULL DEFAULT '1', 
    `mfgpartno` varchar(70) NOT NULL DEFAULT '', 
    `categoryid` int(11) NOT NULL DEFAULT '0', 
    `isaccessory` tinyint(1) NOT NULL DEFAULT '0', 
    `equivalency` double NOT NULL DEFAULT '0', 
    `creationdate` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', 
    `modifieddate` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 
    `lastupdated` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 
    PRIMARY KEY (`productid`), 
    KEY `product_manufacturerID` (`manufacturerid`), 
    KEY `product_categoryID` (`categoryid`), 
    KEY `product_mfgPartNo` (`mfgpartno`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 
/*!40101 SET character_set_client = @saved_cs_client */; 

-- 
-- Table structure for table `search_attribute` 
-- 

DROP TABLE IF EXISTS `search_attribute`; 
/*!40101 SET @saved_cs_client  = @@character_set_client */; 
/*!40101 SET character_set_client = utf8 */; 
CREATE TABLE `search_attribute` (
    `productid` int(11) NOT NULL DEFAULT '0', 
    `attributeid` bigint(20) NOT NULL DEFAULT '0', 
    `valueid` int(11) NOT NULL DEFAULT '0', 
    `localeid` int(11) NOT NULL DEFAULT '0', 
    `setnumber` tinyint(2) NOT NULL DEFAULT '0', 
    `isactive` tinyint(1) NOT NULL DEFAULT '1', 
    PRIMARY KEY (`productid`,`localeid`,`attributeid`,`setnumber`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 
/*!40101 SET character_set_client = @saved_cs_client */; 

-- 
-- Table structure for table `search_attribute_values` 
-- 

DROP TABLE IF EXISTS `search_attribute_values`; 
/*!40101 SET @saved_cs_client  = @@character_set_client */; 
/*!40101 SET character_set_client = utf8 */; 
CREATE TABLE `search_attribute_values` (
    `valueid` int(11) NOT NULL DEFAULT '0', 
    `value` varchar(255) NOT NULL DEFAULT '', 
    `absolutevalue` double NOT NULL DEFAULT '0', 
    `unitid` int(11) NOT NULL DEFAULT '0', 
    `isabsolute` tinyint(1) NOT NULL DEFAULT '0', 
    PRIMARY KEY (`valueid`), 
    KEY `search_attrval_value` (`value`) 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 
/*!40101 SET character_set_client = @saved_cs_client */; 

Количество записей в каждой таблице:

search_attribute является 72000000, search_attribute_values ​​является 350000, продукт 4000000

+0

Добавить индексы в поля, которые вы используете в разделе where. Также рассмотрите возможность использования соединений. – blairmeister

ответ

0

Ваши индексы, поскольку они стоят, все должно быть в порядке. В таблице продуктов есть индекс для категории, и затем он должен присоединиться к этому атрибуту search_attribute, который имеет индекс покрытия для нескольких столбцов, первый из которых является productid (который должен использоваться). Затем он должен присоединиться к search_attribute_values, используя valueid, который является первичным ключом.

Однако по какой-то причине MySQL, похоже, решила сделать несертифицированное чтение в search_attribute, возвращая массивное количество строк, а затем попыталось присоединиться к другим. Возможно, из-за GROUP BY (который, вероятно, вернет странные значения для всех остальных возвращенных столбцов).

Первое, что я хотел бы попробовать - заставить MySQL перестроить статистику индекса (используя ANALYZE TABLE). Тогда он может использовать их с пользой.

В противном случае попробуйте использовать STRAIGHT_JOIN: -

SELECT * 
FROM product 
STRAIGHT_JOIN search_attribute ON product.productid = search_attribute.productid 
STRAIGHT_JOIN search_attribute_values ON search_attribute.valueid = search_attribute_values.valueid 
WHERE product.categoryid = 4800 
GROUP BY search_attribute.valueid 

Однако, какие ценности вы на самом деле хотите, чтобы вернуться? Например, ваш запрос вернет 1 продукт с идентификатором категории 4800 для каждого значения_изначения search_attribute. Какой продукт, который возвращается, не определен, и аналогичным образом предполагается, что несколько атрибутов поиска могут иметь один и тот же значение, а затем тот, который выбран, также не определен.

Хотя это не ошибка и возвращает что-то в MySQL, это даст ошибку в большинстве вариантов SQL.

+0

Выполнение ANALYZE TABLE исправил мои запросы отлично! Спасибо! – Aaron

+0

У меня есть аналогичный вопрос сейчас, см. Здесь: http://stackoverflow.com/questions/34125650/slow-mysql-query-copying-to-tmp-table-using-filesort – Aaron

0

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

Итак, вы создали составной первичный ключ, но вы запрашиваете его с помощью search_attribute.valueid, поэтому необходимо добавить еще один индекс.

ALTER TABLE `search_attribute` ADD INDEX `valueid ` (`valueid `) 
ALTER TABLE `search_attribute` ADD INDEX `productid ` (`productid `) 

Скорее всего это улучшит производительность.

0

Пожалуйста, используйте синтаксис: JOIN...ON

SELECT * 
    FROM product AS p 
    JOIN search_attribute AS sa ON p.productid = sa.productid 
    JOIN search_attribute_values AS sav ON sa.valueid = sav.valueid 
    WHERE p.categoryid = 4800 
    GROUP BY sa.valueid 

Ваш GROUP BY не действует, так как есть много полей (в *), которые не являются ни включены в GROUP BY ни являются агрегаты (COUNT, SUM и т.д.).

InnoDB будет лучше.

Это обмануть его в использовании индекса на CategoryID и не начать с таблицей 72М-строки:

SELECT * 
    FROM 
     (SELECT * 
      FROM product AS p 
      JOIN search_attribute AS sa ON p.productid = sa.productid 
      JOIN search_attribute_values AS sav ON sa.valueid = sav.valueid 
      WHERE p.categoryid = 4800 
    ) x 
    GROUP BY x.valueid 

Но она по-прежнему имеет проблемы с *.

Смежные вопросы