1

我有这样的查询:

SELECT o.id,
        o.archieve,
        listingid,
        orderdate,
        paymentdate,
        os.STATUS,
        o.shippingpreference,
        s.NAME AS store,
        c.fullname AS customer,
        (
            SELECT COUNT(oi.id)
            FROM orders_inventory oi
            WHERE orderid = o.id
        ) AS itemcount,
        (
            SELECT COUNT(op.orderid)
            FROM orders_preorder op
            WHERE op.orderid = o.id
        ) AS itemcountPre,
        a.fullname AS salesrep,
        fOrderProfit(o.id) AS profit,
        o.packtime,
        o.trackingnumber,
        fSentMailToVendor(o.id) AS sentmailtovendors,
        a2.fullname AS adminname
FROM    orders o
        LEFT JOIN orders_status os
                ON os.id = o.statusid
        LEFT JOIN stores s
                ON s.id = o.storeid
        LEFT JOIN customers c
                ON c.id = o.customerid
        LEFT JOIN admins a
                ON a.id = o.salerepresentativeid
        LEFT JOIN admins a2
                ON a2.id = o.adminid
WHERE TRUE AND archieve = '0'
GROUP BY o.id
ORDER BY o.id DESC LIMIT 50

是的,它有点复杂,也许应该优化一下。但我的问题是,相同的查询在旧服务器(mysql v5.5)中运行时间为 0.4 秒,而在具有两个 CPU 和更好硬件(mysql v5.6)的服务器中运行时间为 300 秒。有任何想法吗?


在两台服务器上使用 EXPLAIN EXTENDED 给出 8 行解释,但我相信第一行会有所不同,所以我只列出了第一行比较:

旧服务器:

  • 选择类型:主要
  • 表:o
  • 类型:索引
  • 可能的键:空
  • 关键:主要
  • 关键长度:4
  • 参考:空
  • 行数:50
  • 过滤:102776
  • 额外:使用 where

新服务器:

  • 选择类型:主要
  • 表:o
  • 类型:全部
  • possible_keys: PRIMARY,id,orderdate,customerid,storeid
  • 键:空
  • key_len:空
  • 参考:空
  • 行数:51664
  • 过滤:100
  • 额外:使用where;使用临时的;使用文件排序

注意:顺便说一句,我在使用 EXPLAIN EXTENDED 之前将新服务器中的表类型转换为 InnoDB。

4

1 回答 1

0

我假设表结构是相同的,我很清楚它可能是什么:

5.6 上的优化器与 5.5 中的优化器非常不同。您应该使用 EXPLAIN 运行该语句并查看优化器为您提供了什么。

您可能需要使用 optimizer_switch(打开或关闭设置),或者您可以将 USE INDEX 添加到您的语句中以告诉优化器选择哪个路径。

或者,您可以多次运行查询并“教”优化器采用哪条路径,但这当然不能保证。

我希望这会有所帮助。

添加新数据:

正如您的解释语句所示,请尝试以下操作:

SELECT o.id,
        o.archieve,
        listingid,
        orderdate,
        paymentdate,
        os.STATUS,
        o.shippingpreference,
        s.NAME AS store,
        c.fullname AS customer,
        (
            SELECT COUNT(oi.id)
            FROM orders_inventory oi
            WHERE orderid = o.id
        ) AS itemcount,
        (
            SELECT COUNT(op.orderid)
            FROM orders_preorder op
            WHERE op.orderid = o.id
        ) AS itemcountPre,
        a.fullname AS salesrep,
        fOrderProfit(o.id) AS profit,
        o.packtime,
        o.trackingnumber,
        fSentMailToVendor(o.id) AS sentmailtovendors,
        a2.fullname AS adminname
FROM    orders o use index (primary) -- new change here
        LEFT JOIN orders_status os
                ON os.id = o.statusid
        LEFT JOIN stores s
                ON s.id = o.storeid
        LEFT JOIN customers c
                ON c.id = o.customerid
        LEFT JOIN admins a
                ON a.id = o.salerepresentativeid
        LEFT JOIN admins a2
                ON a2.id = o.adminid
WHERE TRUE AND archieve = '0'
GROUP BY o.id
ORDER BY o.id DESC LIMIT 50
于 2013-09-22T19:39:39.477 回答