MySQL 5 亿行表在带有连接的选择查询中

Posted

技术标签:

【中文标题】MySQL 5 亿行表在带有连接的选择查询中【英文标题】:MySQL 500 million rows table in select query with join 【发布时间】:2012-06-11 07:16:12 【问题描述】:

一旦表格完全填充,我担心以下查询的性能。到目前为止,它正在开发中,并且在虚拟数据方面表现良好。

一旦完全填充,表“adress_zoo”将包含大约 5 亿条记录。 “adress_zoo”表如下所示:

  CREATE TABLE `adress_zoo` 
     ( `adress_id` int(11) NOT NULL, `zoo_id` int(11) NOT NULL, 
     UNIQUE KEY `pk` (`adress_id`,`zoo_id`), 
     KEY `adress_id` (`adress_id`) ) 
     ENGINE=InnoDB DEFAULT CHARSET=latin1;

其他表将包含最多 500 条记录。

完整的查询如下所示:

  SELECT a.* FROM jos_zoo_item AS a 
  JOIN jos_zoo_search_index AS zsi2 ON zsi2.item_id = a.id 
  WHERE a.id IN (   

     SELECT r.id FROM ( 

        SELECT zi.id AS id, Max(zi.priority) as prio 
        FROM jos_zoo_item AS zi 
        JOIN jos_zoo_search_index AS zsi ON zsi.item_id = zi.id 
        LEFT JOIN jos_zoo_tag AS zt ON zt.item_id = zi.id 
        JOIN jos_zoo_category_item AS zci ON zci.item_id = zi.id 
        **JOIN adress_zoo AS az ON az.zoo_id = zi.id** 

        WHERE 1=1 
        AND ( (zci.category_id != 0 AND ( zt.name != 'prolong' OR zt.name is NULL)) 
        OR (zci.category_id = 0 AND zt.name = 'prolong') ) 
        AND zi.type = 'telefoni' 
        AND zsi.element_id = '44d3b1fd-40f6-4fd7-9444-7e11643e2cef' 
        AND zsi.value = 'Small' 
        AND zci.category_id > 15 
        **AND az.adress_id = 5** 

        GROUP BY zci.category_id ) AS r 
  ) 

  AND a.application_id = 6 
  AND a.access IN (1,1) 
  AND a.state = 1 
  AND (a.publish_up = '0000-00-00 00:00:00' OR a.publish_up <= '2012-06-07 07:51:26') 
  AND (a.publish_down = '0000-00-00 00:00:00' OR a.publish_down >= '2012-06-07 07:51:26') 
  AND zsi2.element_id = '1c3cd26e-666d-4f8f-a465-b74fffb4cb14' 

  GROUP BY a.id 
  ORDER BY zsi2.value ASC

查询通常会返回大约 25 条记录。

根据您的经验,此查询的执行是否可以接受(例如 3 秒内响应)? 我可以做些什么来优化它?

按照@Jack 的建议,我用 EXPLAIN 运行了查询并得到了这个:

【问题讨论】:

题外话:下次有人问“mysql 对我的 100k 记录的巨大表会表现良好吗?”时,这个问题将是一个很好的参考资料 【参考方案1】:

这部分是一个重要的限制器:

az.adress_id = 5

MySQL 会将表限制为仅在 adress_id 匹配之前将其与语句的其余部分连接起来的那些记录,因此这将取决于您认为结果集可能有多大。

顺便说一句,您有一个 UNIQUE(adress_id, zoo_id) 和一个单独的 INDEX。有什么特别的原因吗?因为 MySQL 也可以使用生成键的第一部分进行选择。

同样重要的是使用EXPLAIN 了解 MySQL 如何“攻击”您的查询并返回结果。另见:http://dev.mysql.com/doc/refman/5.5/en/execution-plan-information.html

【讨论】:

嗨@Jack,az.adress_id = X 将返回大约 225 条记录。好的,那么我可以删除第二个索引,太好了!在这种情况下,innodb 与 myisam 怎么样? @user1441607 好的,我已经更新了我的答案以包含指向 MySQL 的 EXPLAIN 功能的链接。 再次感谢!我用解释运行它,它似乎在可能的地方使用键?在原始帖子中发布了屏幕截图。 所以我想这可以工作吗?当涉及到更大的表时,我对 MySQL 的执行方式没有经验......最小磁盘大小和 RAM 怎么样?也许已经问过另一个问题? @user1441607 调整 MySQL 服务器以处理这些数据大小完全是另一个主题。但是最好随着数据的增长来处理这个问题……比如说,你在里面添加一半的总数据,看看它是怎么回事;如果有性能问题,您可以开始询问/环顾四周:)【参考方案2】:

为避免子查询,您可以尝试将查询重写为:

SELECT a.* FROM jos_zoo_item AS a 
  JOIN jos_zoo_search_index AS zsi2 ON zsi2.item_id = a.id 
  INNER JOIN 
  (   
     SELECT ** distinct ** r.id FROM ( 

        SELECT zi.id AS id, Max(zi.priority) as prio 
        FROM jos_zoo_item AS zi 
        JOIN jos_zoo_search_index AS zsi ON zsi.item_id = zi.id 
        LEFT JOIN jos_zoo_tag AS zt ON zt.item_id = zi.id 
        JOIN jos_zoo_category_item AS zci ON zci.item_id = zi.id 
        **JOIN adress_zoo AS az ON az.zoo_id = zi.id** 

        WHERE 1=1 
        AND ( (zci.category_id != 0 AND ( zt.name != 'prolong' OR zt.name is NULL)) 
        OR (zci.category_id = 0 AND zt.name = 'prolong') ) 
        AND zi.type = 'telefoni' 
        AND zsi.element_id = '44d3b1fd-40f6-4fd7-9444-7e11643e2cef' 
        AND zsi.value = 'Small' 
        AND zci.category_id > 15 
        **AND az.adress_id = 5** 

        GROUP BY zci.category_id ) AS r 
  ) T
    on a.id = T.id
  where 
  AND a.application_id = 6 
  AND a.access IN (1,1) 
  AND a.state = 1 
  AND (a.publish_up = '0000-00-00 00:00:00' OR a.publish_up <= '2012-06-07 07:51:26') 
  AND (a.publish_down = '0000-00-00 00:00:00' OR a.publish_down >= '2012-06-07 07:51:26') 
  AND zsi2.element_id = '1c3cd26e-666d-4f8f-a465-b74fffb4cb14' 

  GROUP BY a.id 
  ORDER BY zsi2.value ASC

这种方法不会对每个候选行执行子查询。只有在几毫秒内计算出T 才能提高性能。

【讨论】:

一旦我获得所有数据,我将测试这个“调整”。感谢@danihp 您的意见。

以上是关于MySQL 5 亿行表在带有连接的选择查询中的主要内容,如果未能解决你的问题,请参考以下文章

在 Ubuntu 终端中运行带有连接的 MYSQL 选择查询 [关闭]

带有连接和group by子句的选择查询中的MySQL性能问题

MySQL存储引擎和连接查询

MySQL存储引擎和连接查询

mysql在具有1亿行的表上创建索引

如何在 mysql 中使用带有三个表的子查询/连接?