【问题标题】:Slow mysql query, copying to tmp table, using filesort缓慢的mysql查询,复制到tmp表,使用文件排序
【发布时间】:2015-12-07 02:49:02
【问题描述】:

我需要加快这个查询。耗时 12 秒,返回 3917 条记录。我安装的 mySQL 并没有针对性能进行调整,也许我需要修改一些配置变量来帮助提高性能。在查询的大部分时间里,查询都会显示“Copying to tmp table”。

此查询用于生成参数搜索过滤器(即按品牌名称、颜色等过滤搜索结果)。

查询:

SELECT  attributenames.attributeid,
        search_attribute_values.valueid,
        attributenames.name,
        search_attribute_values.value,
        count(search_attribute_values.value) as count,
        search_attribute_values.absolutevalue
    FROM  product
    INNER JOIN  vendorimport
               ON (vendorimport.productid = product.productid
              AND  product.categoryid = 4871)
    INNER JOIN  search_attribute
               ON (search_attribute.productid = product.productid
              AND  search_attribute.localeid = 1)
    INNER JOIN  search_attribute_values
               ON (search_attribute.valueid = search_attribute_values.valueid)
    INNER JOIN  attributenames
               ON (attributenames.attributeid = search_attribute.attributeid
              AND  attributenames.localeid = 1)
    GROUP BY  attributenames.attributeid, search_attribute_values.valueid

解释:

+----+-------------+-------------------------+--------+----------------------------------------------------+----------------------------+---------+---------------------------------------+-------+----------------------------------------------+
| id | select_type | table                   | type   | possible_keys                                      | key                        | key_len | ref                                   | rows  | Extra                                        |
+----+-------------+-------------------------+--------+----------------------------------------------------+----------------------------+---------+---------------------------------------+-------+----------------------------------------------+
|  1 | SIMPLE      | product                 | ref    | PRIMARY,product_categoryID,categoryid_productid    | categoryid_productid       | 4       | const                                 | 38729 | Using index; Using temporary; Using filesort |
|  1 | SIMPLE      | vendorimport            | ref    | productimport_productid                            | productimport_productid    | 5       | microcad.product.productid            |     1 | Using where; Using index                     |
|  1 | SIMPLE      | search_attribute        | ref    | PRIMARY                                            | PRIMARY                    | 8       | microcad.vendorimport.productid,const |     8 | Using where; Using index                     |
|  1 | SIMPLE      | attributenames          | ref    | attributenames_attributeID,attributenames_localeID | attributenames_attributeID | 8       | microcad.search_attribute.attributeid |     4 | Using where                                  |
|  1 | SIMPLE      | search_attribute_values | eq_ref | PRIMARY                                            | PRIMARY                    | 4       | microcad.search_attribute.valueid     |     1 |                                              |
+----+-------------+-------------------------+--------+----------------------------------------------------+----------------------------+---------+---------------------------------------+-------+----------------------------------------------+

架构:

--
-- 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`),
  KEY `categoryid_productid` (`categoryid_productid`)
) 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 为 72,000,000, search_attribute_values 是 350,000, 产品为 4,000,000

【问题讨论】:

  • 首先,我建议您摆脱默认值(尤其是在 varchar 列上)并使用 NULL。此外,您应该阅读索引(集群和非集群)并考虑在查询中经常引用的列上使用它们。最后,查看查询的查询计划,看看瓶颈在哪里。
  • 我已将 varchar 列的默认值更改为 NULL。我已经在我经常使用的列上有很多索引。我有兴趣加快这个特定的查询。
  • 我将首先在category_id, product_id 上创建一个索引,然后运行一个简单的查询select product_id from product where category_id = 4871。这是您的查询将运行的最快速度。然后从那里构建。
  • @JRD 我将 (categoryid,productid) 的索引添加到产品表中,现在解释显示“使用索引”,我已经更新了原始问题以显示它。查询仍然较慢。
  • 再次查看查询,您 GROUP BY 来自 2 个不同表的 attributeid 和 valueid,但它们的值都在 search_attribute 表上。如果您切换到从 search_attribute 获取值,并对来自 search_attribute 的值进行分组,那么它可能会利用 search_attribute 表上这些字段的索引。

标签: mysql performance optimization


【解决方案1】:

NULL vs NOT NULL -- 使用NOT NULL,除非您有使用NULL 的商业原因。

在每个表上使用带有相关PRIMARY KEY 的 InnoDB。那可能会更快。

在有意义的地方“使用索引”会有所帮助。

product.categoryid = 4871 不属于vendorimportON 子句;将其移至 WHERE 子句。 (这不会加快速度。)

您的查询不能进一步优化——它必须完成所有的 JOIN 并传递所有的行。

但是……你真的想要 3917 行的输出吗?你能应付吗?也许您只想要其中的几个并且可以在 SELECT 期间过滤它们?这可以加快速度。

【讨论】:

  • 查询生成具有特定属性和值的所有产品,然后我使用 GROUP BY 为每个值(Microsoft)属性(品牌名称)生成计数。示例:品牌名称:联想 (125) 微软 (40)。我不知道该怎么办..我只是在考虑切换到 Apache Solr ......但我宁愿让它更快地工作。我添加了搜索结果的图片,左侧的过滤器是使用此查询创建的。
猜你喜欢
  • 2012-02-12
  • 1970-01-01
  • 1970-01-01
  • 2013-09-15
  • 2012-01-15
  • 2011-02-15
  • 1970-01-01
  • 2023-04-09
  • 1970-01-01
相关资源
最近更新 更多