mysql优化sql查询

kq4fsx7k  于 2021-06-20  发布在  Mysql
关注(0)|答案(3)|浏览(317)

请帮我优化下一个sql查询

SELECT Executor_service.*, Executor.*
FROM Executor_service
INNER JOIN Executor ON Executor.user_id = Executor_service.executor_id
LEFT JOIN Cancel ON Cancel.executor_id = Executor.user_id AND Cancel.city_id = 3538 
WHERE Cancel.order_id IS NULL
AND Executor.user_id != 236 
AND Executor_service.service_id = 511
AND Executor_service.status = 'free'
AND Executor_service.mstatus = 'work'
AND Executor_service.city_id =3538
AND Executor.balance > 0
AND Executor.status = 'free'
ORDER BY Executor.rate DESC
LIMIT 1

这个代码非常慢(10-15s)->>左连接cancel on cancel.executor\u id=executor.user\u id和cancel.city\u id=3538
更新1
我需要获取executor.user\u id
表执行器具有下一个结构执行器
表executor\u service是have next struct executor\u service
表cancel是具有下一个结构cancel
表executor是系统中存在的所有executors。
表executor\u service是每个executor的exist服务,其中executor.user\u id=executor\u service.executor\u id
表cancel是关于取消订单的存在信息(取消人和原因)
我需要从指定的城市获取一个具有最高评级(而不是零余额)的executor,该城市根据executor\u service表(executor\u service.service\u id)中的指定id执行服务。同时,cancel表不应包含给定执行器为此服务被点击的记录
更新2
我改变了

SELECT Executor_service.*, Executor.*
FROM Executor_service
INNER JOIN Executor ON Executor.user_id = Executor_service.executor_id

SELECT Executor.user_id
FROM Executor
INNER JOIN Executor_service ON Executor.user_id = Executor_service.executor_id

需要3-5秒,但查询时间太长了。

k3fezbri

k3fezbri1#

尝试索引: executor_service(city_id, service_id, status, mstatus, user_id) .
我猜 join 键已具有索引。

iqjalb3h

iqjalb3h2#

稍微重新构造了查询。我更喜欢看表“a”直接连接到“b”和“b”到“c”的位置,等等。。我还尝试将left side table.column保留在左侧,将left side table.column保留在右侧。另外,对于特定于表的条件,我尝试将其直接放在连接处。这有助于我形象化的条件是什么,什么可能有助于确定优化指标。。。

SELECT 
      ES.*, 
      E.*
   FROM 
      Executor_service ES
         INNER JOIN Executor E
            ON ES.executor_id = E.user_id
            AND ES.status = E.status
            AND E.balance > 0
         LEFT JOIN Cancel C
            ON ES.executor_id = C.executor_id
           AND ES.City_ID = C.city_id
   WHERE 
          ES.service_id = 511
      AND ES.status = 'free'
      AND ES.mstatus = 'work'
      AND ES.city_id = 3538
      AND ES.executor_id != 236
      AND C.order_id IS NULL
   ORDER BY 
      E.rate DESC
   LIMIT 1

也就是说,有一对可传递的关系(如果a=b和b=c,那么a=c),比如您对executor的userid的标准,它与executor\u service.executor\u id相同,所以我把它移到“es”(executor\u service的别名)的where子句中。在左侧更正cancel代码的连接,并在where中显式查找is null。
至于索引,我将确保以下内容对您有所帮助

Executor_Service table -- index on (service_id, city_id, mstatus, status )
Executor table -- index on ( user_id, status, balance ).  
Cancel table -- index on ( executor_id, city_id )

通过在索引中包含余额,使得查询的覆盖索引不需要转到数据页,并且可以直接从索引中获取值。

uinbv5nw

uinbv5nw3#

因为你没有从你计划的表中选择任何东西 LEFT JOIN ,完全可以省略。使用 INNER JOIN 过滤你的结果,但是 LEFT (OUTER) JOIN 没有,所以没有必要:

SELECT Executor_service.*, Executor.*
    FROM Executor_service
         INNER JOIN Executor ON Executor.user_id = Executor_service.executor_id
   WHERE     Executor.user_id != 236
         AND Executor_service.service_id = 511
         AND Executor_service.status = 'free'
         AND Executor_service.mstatus = 'work'
         AND Executor_service.city_id = 3538
         AND Executor.balance > 0
         AND Executor.status = 'free'
ORDER BY Executor.rate DESC
    LIMIT 1

看看是否适合你。如果你真的打算用 LEFT JOINCancel 比这更好的方法。
性能优化的问题在于,您当前并没有真正使用 LEFT JOIN 完全。如果您真的想使用left join,就不能在where子句中使用表的列。把那个连接变成内部连接。
另一件小事:看看代码,最好是连接表 Cancel 以及 Executor_service 通孔 city_id 列而不是写入 city_id =3538 两次:
带有这些更正的代码如下(保留 Cancel 中的表 INNER JOIN ,就像以前一样):

SELECT Executor_service.*, Executor.*
    FROM Executor_service
         INNER JOIN Executor ON Executor.user_id = Executor_service.executor_id
         INNER JOIN Cancel ON Cancel.executor_id = Executor.user_id AND Cancel.city_id = Executor_service.city_id
   WHERE     Cancel.order_id IS NULL
         AND Executor.user_id != 236
         AND Executor_service.service_id = 511
         AND Executor_service.status = 'free'
         AND Executor_service.mstatus = 'work'
         AND Executor_service.city_id = 3538
         AND Executor.balance > 0
         AND Executor.status = 'free'
ORDER BY Executor.rate DESC
    LIMIT 1

另外,如果你想使用 LEFT JOIN 筛选结果以便排除 Cancel 表(如注解中所述),则可以使用以下代码:

SELECT Executor_service.*, Executor.*
    FROM Executor_service
         INNER JOIN Executor ON Executor.user_id = Executor_service.executor_id
   WHERE     Executor.user_id != 236
         AND Executor_service.service_id = 511
         AND Executor_service.status = 'free'
         AND Executor_service.mstatus = 'work'
         AND Executor_service.city_id = 3538
         AND Executor.balance > 0
         AND Executor.status = 'free'
         AND NOT EXISTS (SELECT Cancel.order_id
                           FROM Cancel
                          WHERE Cancel.executor_id = Executor.user_id AND Cancel.city_id = Executor_service.city_id)
ORDER BY Executor.rate DESC
    LIMIT 1

或者,您可以使用 LEFT JOIN (添加了 Cancel.order_id 然后移动 WHERE Cancel.order_id IS NULL 外部查询中的条件。

热释光;博士:

如果你真的想在 Cancel 你可以把它全部省略。如果要将其用作排除连接到中现有数据的数据 Cancel 表,然后您应该重写它作为在上一个代码中发布的(或通过子查询)。如果没有这些-这是很难优化代码不知道背后的数据。。。在这种情况下,我至少希望这些小小的输入能帮助你更好地理解你真正想要的和得到的。

相关问题