MySQL - 如何优化此查询?

时间:2010-06-28 05:04:26

标签: mysql sql performance query-optimization

以下查询有效,但10个记录(2秒)非常慢。分析说它创建了一个tmp表,但我不确定原因。

基本上,我正在加入当前用户,加入acl小组,以获取他们所在的所有群组,然后将小组加入公司,获取他们所在的所有公司,然后将公司加入订单,得到所有订单..

如果我删除此行

ORDER BY orders.created_on DESC 

然后查询在0.06秒内执行(更可接受)..

帮助,关于如何优化的任何想法?非常感谢:))

SELECT
    orders.uuid,
    companies.name as company_name
FROM
    users u
JOIN    
    users_acl_groups g on   u.uuid = g.user_uuid
JOIN
    users_acl acl on (acl.user_uuid = u.uuid or acl.group_uuid = g.group_uuid) 
JOIN 
    companies on acl.item_uuid = companies.uuid
JOIN
    orders on companies.uuid = orders.company_uuid
WHERE
    u.uuid = 'DDEC8073-5056-C000-01ED583A51CBCA32' and orders.status <> ''
ORDER BY orders.created_on DESC 

limit 0, 10;

更新,查询的解释..

  

1 SIMPLE命令所有9403使用   临时;使用filesort

     

1 SIMPLE acl ALL 1859使用where;   使用连接缓冲区

     

1 SIMPLE g ALL 2005使用where;   使用连接缓冲区

     

1 SIMPLE公司eq_ref PRIMARY PRIMARY 52 table.orders.company_uuid 1

     

1 SIMPLE u ALL 33595使用where;   不同;使用连接缓冲区

5 个答案:

答案 0 :(得分:2)

您是否考虑过将 fact table 样式设计作为非规范化步骤?

基本上它是一种多对多的交集表,例如:

CREATE TABLE user_order_fact (
  user_uuid ...
  order_uuid ...
  order_created_on ...
  order_status ...
  company_name ...,
  primary key (user_uuid, order_uuid),
  key (user_uuid, order_status, order_created_on, order_uuid, company_name)
);

... fill with data ...

SELECT
    order_uuid,
    company_name
FROM
    user_order_fact
WHERE
    user_uuid = 'DDEC8073-5056-C000-01ED583A51CBCA32' and order_status <> ''
ORDER BY order_created_on DESC 

limit 0, 10;

我在猜测复合指数。你必须进行实验,直到你做对了。基本上你正试图让优化器计划报告使用索引

当然这是以冗余方式存储数据并以非规范化形式存储,因此您需要设置一些触发器以使其与规范化表保持同步。

答案 1 :(得分:0)

确保“orders.created_on”有一个索引......如果确实如此,那么Bill在顶部的方法将是最好的,但需要一些工作。

答案 2 :(得分:0)

如果不了解现有索引或每个表的数量,很难回答。

此外,没有关于模型的大量信息......查询是否会返回所有结果?

所有用户都属于某个群组吗?似乎不是......并且查询不会返回组外的用户。

组是否可以属于某个组,需要递归查询?

答案 3 :(得分:0)

我不确定它的确切原因可能需要2秒。这个查询获取10条记录是不可能的,但这里看到的是

  1. acl.user_uuid = u.uuid or acl.group_uuid = g.group_uuid

    基于UID的加入,也许你也是 用它作为主键 上面回答。

  2. ORDER BY orders.created_on。在Order by上使用date不会比使用PK或任何整数值更优化 更合适。

  3. orders.status <> ''如果在表上使用任何索引,则没有索引 可以在此查询中使用,因为 不是运营商和类似 在任何查询中使用时,运算符不使用索引。

  4. 表格中的记录数量可能是另一个原因,但仅限于上述因素。否则它也可以处理大量音量。
  5. 我认为主要的贡献因素是在联接中使用UID 因此,您的查询中可以看到所有三个避免条件,这可能会使您的查询变得懒惰

答案 4 :(得分:0)

很少有想法:

您实际上没有在查询中选择orders.created_on。所以没有必要对该列进行排序。也许,选择它(SELECT orders.created_on ...)会有助于表现(只是猜测 - 我不知道我在这里说什么)。

如果查询返回的记录数量不足,您可以随时在应用程序中进行排序。

有时使用N个小查询而不是1个大sql查询会更明智。伪代码:

user_id = get_one("SELECT uuid FROM users WHERE ...");
group_ids = get_many("SELECT uuid FROM groups WHERE user_uuid = " + user_id);
comps_ids = get_many("SELECT DISTINCT item_uuid FROM acls WHERE user_uuid = " + user_id + " OR group_uuid IN " + groups_ids.to_q());
orders = get_many("SELECT * FROM orders WHERE company_uuid IN " + comps_ids.as_q() + " WHERE status <> '' ORDER BY created_on");