在MySql中通过限制来优化订单

时间:2019-03-20 17:42:01

标签: mysql sql query-performance

我有300万个记录表,称为“交易”。

CREATE TABLE transactions(
  id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY,
  lookupAId int(6) NOT NULL,
  .....
  updateDate TIMESTAMP
)

在最坏的情况下,用户将不指定过滤器,查询将如下所示:

select * from transactions
   join lookupA on (well indexed columns) 
   .. ( 12 lookup table joins) 
order by updateDate limit 500

没有 order by 子句,查询将以毫秒为单位运行,但是使用 order by 大约需要一分钟。该表预计将增长到12-15百万条记录。

  1. 我的SLA将在一秒钟内获得结果,这在MySql中是可能的吗?
  2. 如何优化order by子句以使其执行。

我在AWS的xLarge内存优化RDS实例中运行MySql 5.7

UPDATE 1 updateDate具有时间成分并被索引(B树,非唯一)

更新2 可以,尽管我不知道为什么

SELECT * FROM (select * from transactions order by updateDate) transactions
   join lookupA on (well indexed columns) 
   .. ( 12 lookup table joins) 
   limit 500

4 个答案:

答案 0 :(得分:1)

如果您还没有的话,ORDER BY肯定会从索引中受益:

create index ix1 on transactions (updateDate);

答案 1 :(得分:1)

在用limit限制查询大小之前,MySQL可能在查询上做了很多工作。这似乎是MySQL的一个已知弱点。

尝试在进行联接之前从子查询的事务中进行选择以限制结果集的大小。

SELECT * FROM (select * from transactions order by updateDate limit 500) transactions
   join lookupA on (well indexed columns) 
   .. ( 12 lookup table joins) 

答案 2 :(得分:0)

解决此问题的常用技术:

SELECT ... JOIN ...
    LIMIT ...

要去:

  1. 进行最少的工作来找到会影响PRIMARY KEY行的行的LIMIT值。
  2. 将这些ID放入JOINs中以获取其余信息。

正如您所查询的那样,优化器会全力以赴,简单地完成所有JOIN(尽最大可能优化每个),生成一个大的(很多行,很多列)中间表,然后应用{ {1}}(对许多列中的许多行进行排序)和ORDER BY(对其中一些行进行交付)。

使用LIMIT(并且该表在表中选择以INDEX(OrderDate)开始的表中),Optimizer至少可以考虑使用索引。但这可能是最坏的情况-如果没有500行怎么办?反正它将完成所有工作!

答案 3 :(得分:0)

优化器不知道表是简单的“查找”表。必须准备查找0行或多于1行。

情况1:您知道每个查找(JOINed)表中的每一行都恰好有1行:

情况2:您知道每个查询表中最多有1行。

在这两种情况下,以下都是重写查询的有效方法:

SELECT  t.a, t.b, ...
        ( SELECT name FROM LU1 WHERE id = t.name_id ) AS name, 
        ( SELECT foo  FROM LU1 WHERE id = t.foo_id ) AS foo, 
        ...
    FROM transactions AS t
    ORDER BY t.OrderDate
    LIMIT ...

INDEX(OrderDate)
INDEX(id)  -- for each LU table, unless there is already `PRIMARY KEY(id)`

查询的这种表达方式将重点在于准确地遍历500行,并按OrderDate进行预排序,每行查找12个内容。

从语义上讲,它与情况2(LEFT JOIN)是等效的,因为它在没有映射的情况下为NULL(等)提供了name

从技术上讲,情况1是不同的。如果查找失败,JOIN将无法对行进行计数,但我的修改将保留该行,并显示NULL