【问题标题】:Lots of temporary tables in MySQLMySQL中有很多临时表
【发布时间】:2013-11-03 02:01:59
【问题描述】:

我正在运行的网站有以下两个非常重复的查询。在 MySQL innoDB 进程中可以看到它们花费了大量时间,每当我看到这些进程时,它们都会继续创建临时表并且需要很长时间才能执行占用大量内存和 CPU。

它们真的很糟糕,我设法优化了这些......但我无法做到这一点。

$getmoddetails =    "SELECT a.id, a.name, a.defvar, a.description, a.icon, a.thumb, a.average_rating, a.total_rating, c.rating, a.group_access, d.long_name, a.editor_id, e.users_count
        FROM dir_cat_item AS b
        INNER JOIN dir_item AS a ON a.id = b.item_id
        AND a.status = 'O'
        LEFT JOIN dir_item_notation_user_map AS c ON a.id = c.item_id
        AND c.user_id =%u 
        LEFT JOIN users AS d ON d.id = a.editor_id
        LEFT JOIN (SELECT item_id, COUNT(*) AS users_count
            FROM   module
            GROUP BY item_id) AS e ON e.item_id = b.item_id
        WHERE a.id=%u";


$getnbModules_by_col = "SELECT 
                            posx,COUNT(posx) as nb 
                        FROM module WHERE 
                            user_id = %u 
                            AND profile_id = %u 
                        GROUP BY posx
                        ORDER BY posx ASC";

模块上的表索引

- item_id - 用户身份 - profile_id - 独特的

对于用户表

- ID - 用户名

任何建议请...

更新:-

CREATE TABLE IF NOT EXISTS `module` (
  `item_id` mediumint(8) unsigned NOT NULL DEFAULT '0',
  `user_id` int(10) unsigned NOT NULL DEFAULT '0',
  `profile_id` int(3) unsigned NOT NULL DEFAULT '0',
  `posx` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `posy` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `posj` tinyint(3) unsigned NOT NULL DEFAULT '0',
  `x` smallint(5) unsigned NOT NULL DEFAULT '0',
  `y` smallint(5) unsigned NOT NULL DEFAULT '0',
  `typ` char(1) CHARACTER SET utf8 NOT NULL DEFAULT 'D',
  `variables` text COLLATE utf8_unicode_ci,
  `uniq` smallint(5) unsigned NOT NULL DEFAULT '1',
  `blocked` tinyint(1) unsigned NOT NULL DEFAULT '0',
  `minimized` tinyint(1) unsigned NOT NULL DEFAULT '0',
  `old_id` tinyint(3) unsigned DEFAULT NULL,
  `feed_id` mediumint(8) unsigned NOT NULL DEFAULT '0',
  `shared` varchar(33) COLLATE utf8_unicode_ci DEFAULT NULL,
  `currentview` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL,
  KEY `item_id` (`item_id`,`user_id`,`profile_id`,`uniq`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;

item_id 18  A   No  
user_id 393467  A   No
profile_id  393467  A   No
uniq    393467  A   No

提前谢谢你

【问题讨论】:

  • EXPLAIN PLAN 并完成SHOW CREATE TABLE 报表结果

标签: mysql sql innodb


【解决方案1】:

为了获得第二个查询的最佳性能,您需要在 module 表上建立一个适当的索引,例如

...  ON module (user_id, profile_id, posx)

对于第一个查询,您可能会受益于 module 表上的不同索引:

... ON module (item_id)

但是如果没有表定义、数据类型和列的基数,真的不可能给出明确的建议。

在您的第一个查询中,我建议您在内联视图(派生表)中添加一个谓词,别名为e。我不认为 MySQL 将谓词从外部查询推送到内联视图。

    ( SELECT item_id
           , COUNT(*) AS users_count
        FROM module
       WHERE item_id = %u
       GROUP BY item_id
    ) AS e

您需要在 WHERE 子句中提供与在外部查询的 WHERE 子句中提供的值相同的值。从我那里读到的...

e.item_id = b.item_id = a.id = %u

通过在该内联视图中添加 WHERE 子句,应该会减少从模块表中检索到的行数,并且该派生表将只有一行。具有item_id 前导列的索引将是覆盖索引。 EXPLAIN PLAN 应该显示Using index 而不是Using filesort


如果您的第一个查询拉回的行数相对较少,您可能会考虑在模块表上使用相关子查询,而不是在您的第一个查询中连接到派生表(别名为 e)(以避免实现大型派生表)。 (然而,一般来说,相关子查询可能是真正的性能杀手。但在某些情况下,外部查询拉回少量行,子查询的重复执行实际上可以比生成大型派生表执行得更好,后者你只需要几行。)

SELECT a.id
     , a.name
     , a.defvar
     , a.description
     , a.icon
     , a.thumb
     , a.average_rating
     , a.total_rating
     , c.rating
     , a.group_access
     , d.long_name
     , a.editor_id
     , ( SELECT SUM(1)
           FROM module e
          WHERE e.item_id = b.item_id
            AND e.item_id = %u
       ) AS users_count
  FROM dir_cat_item b
  JOIN dir_item a 
    ON a.id = b.item_id
   AND b.item_id = %u 
   AND a.status = 'O'
  LEFT
  JOIN dir_item_notation_user_map c 
    ON c.item_id = a.id
   AND c.item_id = %u
   AND c.user_id = %u
  LEFT
  JOIN users d
    ON d.id = a.editor_id
 WHERE a.id = %u

【讨论】:

  • 嗨斯宾塞,感谢您的回复..我已经为第二个查询和亲切度添加了查询结构..
  • 对于第二个查询,你有关于 user_id 和 profile_id 的相等谓词,所以这些需要是索引中的 前导 列,用于索引范围扫描;下一列需要是posx;使用我建议的索引,MySQL 可能能够在没有文件排序操作的情况下执行 GROUP BY。那应该是一个覆盖索引,所以EXPLAIN PLAN 应该在 Extra 列中显示“使用索引”,而不应该显示“使用文件排序”。
  • 更新的答案增加了在第二个查询 WHERE item_id = %u 中将谓词添加到内联视图的建议。
  • 嗨 Spencer.. 谢谢你关于 (SELECT SUM(1) FROM module e WHERE e.item_id = b.item_id ) AS users_count 它扫描表中的所有记录.. 我可以看到使用解释有什么办法可以减少它..
  • @monnmona:添加谓词(即 WHERE 子句)。我更新了我的答案。我阅读您的查询的方式,您提供的值 (%u) = a.id, = b.item_id, =c.item_id, = e.item_id。有时,您可以通过在任何地方指定相等谓词来帮助优化器...还可以尝试添加 b.item_id = %u 更新的查询添加 b.item_id = %uc.item_id = %u 等。还可以考虑将 item_id 列作为前导列的索引.
猜你喜欢
  • 1970-01-01
  • 2014-04-30
  • 2020-10-26
  • 1970-01-01
  • 2017-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多