英文:
SQL query latency inconsistencies
问题
我已经进行了带有和不带有ORDER BY子句的查询,实际上,不排序的查询要快得多。我不能确定原因,但我最好的猜测是与主键索引有关。
当我使用ORDER BY o.id ASC
/ 不排序时,我的查询大约需要3-4秒,而ORDER BY o.id DESC
则在30毫秒内运行。
我在o.attached_offline_id
、o.total_payable_amount
、o.updated_at
和o.status
以及o.id
、u.id
上创建了索引,但它们似乎不能加速我的查询,对于如何更好地为我的列创建索引的建议非常受欢迎,因为我对编写高性能的SQL不太有信心。
这是我的基本查询:
SELECT u.id as user_id, u.phone_number, o.id as order_id,
o.total_payable_amount as amount, o.updated_at AS order_date
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'Completed' AND o.payment_status = 'Completed'
AND o.total_payable_amount >= 1
AND o.attached_offline_id IS NULL AND o.updated_at >= DATE('2023-02-01');
谢谢!
编辑1:以下是大家要求的一些额外信息:
-
是的,订单和用户之间存在外键关系,外键关系是在u.id = o.user_id上定义的。
-
show create table orders;
和show create table users;
的结果对我来说有点太大了,因为表有很多字段和约束,所以我将其省略掉,因为我已经提到了上面的外键关系,我认为这是大家在寻找的内容。 -
我的MySQL版本是5.7.37。
-
EXPLAIN
给我以下结果:
id|select_type|table|partitions|type |possible_keys |key |key_len|ref |rows |filtered|Extra |
--+-----------+-----+----------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------+-------+------------------+------+--------+----------------------------------+
1|SIMPLE |o | |ref |orders_user_id_foreign,total_payable_amount,payment_status,status,orders_updated_at_IDX,orders_attached_offline_id_IDX,orders_total_payable_amount_IDX,orders_status_IDX,orders_user_id_IDX|orders_status_IDX|2 |const,const |831158| 8.09|Using index condition; Using where|
1|SIMPLE |u | |eq_ref|PRIMARY |PRIMARY |4 |vidyakul.o.user_id| 1| 100.0| |
英文:
I've made a query with and without the ORDER BY clause, and it is actually much much faster without the ordering. I can't tell why, but my best guess is it's somehow related to the PRIMARY KEY index.
When I use ORDER BY o.id ASC
/ Don't order it, my query runs in around 3-4 seconds, whereas ORDER BY o.id DESC
runs it in 30ms.
I've made indexes on o.attached_offline_id
, o.total_payable_amount
, o.updated_at
and o.status
, and o.id, u.id are primary keys, but they don't seem to speed up my query, any suggestions on how to better index my columns are very welcome, since I'm not very confident about writing performant SQL.
This is my basic query:
SELECT u.id as user_id, u.phone_number, o.id as order_id,
o.total_payable_amount as amount, o.updated_at AS order_date
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'Completed' AND o.payment_status = 'Completed'
AND o.total_payable_amount >= 1
AND o.attached_offline_id IS NULL AND o.updated_at >= DATE('2023-02-01');
Thanks!
EDIT 1: Here is some additional info everyone requested:
-
Yes, there is a FK relation between orders and users on u.id = o.user_id.
-
show create table orders;
andshow create table users;
results are a bit too big for me to write here, since the tables have a lot of fields and constraints, so I'll omit it here since I've mentioned the FK relation above and think that's what everyone was looking for. -
My mysql version is 5.7.37
-
EXPLAIN
gives me:
id|select_type|table|partitions|type |possible_keys |key |key_len|ref |rows |filtered|Extra |
--+-----------+-----+----------+------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------+-------+------------------+------+--------+----------------------------------+
1|SIMPLE |o | |ref |orders_user_id_foreign,total_payable_amount,payment_status,status,orders_updated_at_IDX,orders_attached_offline_id_IDX,orders_total_payable_amount_IDX,orders_status_IDX,orders_user_id_IDX|orders_status_IDX|2 |const,const |831158| 8.09|Using index condition; Using where|
1|SIMPLE |u | |eq_ref|PRIMARY |PRIMARY |4 |vidyakul.o.user_id| 1| 100.0| |
答案1
得分: 0
你需要一个复合索引,而不是许多单列索引:
索引(status,payment_status,attached_offline_id,--“=”测试
updated_at)--“范围”测试最后
在我的索引菜谱中可以找到更多信息。
(附注:DATE('2023-02-01')
可以简写为'2023-02-01'
。)
英文:
You need a composite index, not lots of single-column indexes:
INDEX(status, payment_status, attached_offline_id, -- "=" test
updated_at) -- "range" test last
More in my Index Cookbook
(PS: DATE('2023-02-01')
can be written simply '2023-02-01'
.)
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论