优化订单,限制在 MySql
Optimizing order by with a limit in MySql
我有一个名为 "transactions" 的 300 万条记录 table 。
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 子句查询 运行s 以毫秒为单位,但是使用 order by 大约需要一个分钟。 table 预计将增长到 12-15 百万条记录。
- 我的 SLA 是在一秒钟内得到结果,在 MySql 内可能吗?
- 如何优化 order by 子句以实现此效果。
I 运行 MySql AWS 中 xLarge 内存优化 RDS 实例中的 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
如果您还没有它,ORDER BY
肯定会从索引中受益:
create index ix1 on transactions (updateDate);
MySQL 可能在使用 limit 限制查询大小之前对查询做了很多工作。这似乎是 MySQL.
的一个已知弱点
尝试从子查询中的事务中执行 select 以在执行连接之前限制结果集的大小。
SELECT * FROM (select * from transactions order by updateDate limit 500) transactions
join lookupA on (well indexed columns)
.. ( 12 lookup table joins)
解决这个问题的常用技巧:
SELECT ... JOIN ...
LIMIT ...
是:
- 做最少的工作来找到影响
LIMIT
行的行的 PRIMARY KEY
值。
- 将这些 ID 填入
JOINs
以获取其余信息。
当你的查询出现时,优化器会举起手来简单地做所有的JOIN
(尽可能地优化每一个),生成一个大的(很多行,很多列)中间table,然后应用 ORDER BY
(对许多列的许多行进行排序)和 LIMIT
(提供其中一些行)。
使用 INDEX(OrderDate)
(并且该列在 table 中,它选择以 JOINing
开始)优化器至少可以考虑使用索引。但这可能是最坏的情况——如果没有 500 行怎么办?它无论如何都会完成所有工作!
优化器不知道 table 是一个简单的 "lookup" table。必须准备查找0行或多于1行。
情况 1:您知道每个查找中正好有 1 行 (JOINed
)tables:
情况 2:您知道每次查找中最多有 1 行 table。
在这两种情况下,以下是重写查询的有效方法:
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
),因为它在没有映射时为 name
(等)给出 NULL
。
从技术上讲,案例 1 并不相同。如果查找失败,JOIN
将无法计算该行,但我的重新制定将保留该行,显示 NULL
.
我有一个名为 "transactions" 的 300 万条记录 table 。
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 子句查询 运行s 以毫秒为单位,但是使用 order by 大约需要一个分钟。 table 预计将增长到 12-15 百万条记录。
- 我的 SLA 是在一秒钟内得到结果,在 MySql 内可能吗?
- 如何优化 order by 子句以实现此效果。
I 运行 MySql AWS 中 xLarge 内存优化 RDS 实例中的 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
如果您还没有它,ORDER BY
肯定会从索引中受益:
create index ix1 on transactions (updateDate);
MySQL 可能在使用 limit 限制查询大小之前对查询做了很多工作。这似乎是 MySQL.
的一个已知弱点尝试从子查询中的事务中执行 select 以在执行连接之前限制结果集的大小。
SELECT * FROM (select * from transactions order by updateDate limit 500) transactions
join lookupA on (well indexed columns)
.. ( 12 lookup table joins)
解决这个问题的常用技巧:
SELECT ... JOIN ...
LIMIT ...
是:
- 做最少的工作来找到影响
LIMIT
行的行的PRIMARY KEY
值。 - 将这些 ID 填入
JOINs
以获取其余信息。
当你的查询出现时,优化器会举起手来简单地做所有的JOIN
(尽可能地优化每一个),生成一个大的(很多行,很多列)中间table,然后应用 ORDER BY
(对许多列的许多行进行排序)和 LIMIT
(提供其中一些行)。
使用 INDEX(OrderDate)
(并且该列在 table 中,它选择以 JOINing
开始)优化器至少可以考虑使用索引。但这可能是最坏的情况——如果没有 500 行怎么办?它无论如何都会完成所有工作!
优化器不知道 table 是一个简单的 "lookup" table。必须准备查找0行或多于1行。
情况 1:您知道每个查找中正好有 1 行 (JOINed
)tables:
情况 2:您知道每次查找中最多有 1 行 table。
在这两种情况下,以下是重写查询的有效方法:
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
),因为它在没有映射时为 name
(等)给出 NULL
。
从技术上讲,案例 1 并不相同。如果查找失败,JOIN
将无法计算该行,但我的重新制定将保留该行,显示 NULL
.