SQL查询延迟不一致

huangapple go评论65阅读模式
英文:

SQL query latency inconsistencies

问题

我已经进行了带有和不带有ORDER BY子句的查询,实际上,不排序的查询要快得多。我不能确定原因,但我最好的猜测是与主键索引有关。

当我使用ORDER BY o.id ASC / 不排序时,我的查询大约需要3-4秒,而ORDER BY o.id DESC则在30毫秒内运行。

我在o.attached_offline_ido.total_payable_amounto.updated_ato.status以及o.idu.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:以下是大家要求的一些额外信息:

  1. 是的,订单和用户之间存在外键关系,外键关系是在u.id = o.user_id上定义的。

  2. show create table orders;show create table users; 的结果对我来说有点太大了,因为表有很多字段和约束,所以我将其省略掉,因为我已经提到了上面的外键关系,我认为这是大家在寻找的内容。

  3. 我的MySQL版本是5.7.37。

  4. 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:

  1. Yes, there is a FK relation between orders and users on u.id = o.user_id.

  2. show create table orders; and show 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.

  3. My mysql version is 5.7.37

  4. 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'.)

huangapple
  • 本文由 发表于 2023年6月8日 14:32:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/76429162.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定