我有一个相当简单的查询,返回所有购买给一个给定的用户,搜索由他的政府发放的身份证。文档可以放在两个不同的表中。
仅使用左联接的查询运行非常慢,仅为- 11分钟。
如果不是"OR",而是运行两个单独的查询(由一个UNION
加入),它们将在4秒内产生相同的精确输出。
尽管有可能,但由于外部因素,最好避免使用UNION。
我是不是漏掉了什么明显的东西导致了如此巨大的差距?
是否有一种合理的方法来修复左只连接查询,使其在10秒内返回?
标准查询:
SELECT
purchase.id
FROM
purchase
LEFT OUTER JOIN user on purchase.buyer = user.id
LEFT OUTER JOIN user_documents on user.id = user_documents.user
LEFT OUTER JOIN buyer_info on purchase.id = buyer_info.purchase
WHERE documents.value = '123' OR buyer_info.document = '123'
联合使用的例子:
SELECT
purchase.id
FROM
purchase
LEFT OUTER JOIN user ON purchase.buyer = user.id
LEFT OUTER JOIN user_documents ON user.id = user_documents.user
WHERE documents.value = '123'
UNION
SELECT
purchase.id
FROM
purchase
LEFT OUTER JOIN buyer_info ON purchase.id = buyer_info.purchase
WHERE buyer_info.document = '123'
查询期间在所有表中使用的所有字段都是索引字段。
购买和BUYER_INFO表:~3200万条记录。
用户表:~1600万条记录。
USER_DOCUMENTS表:~800万条记录。
以下是简化表的说明:
PURCHASE
| Field | Type | Null | Key | Default |
| id | bigint(20) | NO | PRI | NULL |
| buyer | bigint(20) | YES | MUL | NULL |
USER
| Field | Type | Null | Key | Default |
| id | bigint(20) | NO | PRI | NULL |
USER_DOCUMENTS
| Field | Type | Null | Key | Default |
| id | bigint(20) | NO | PRI | NULL |
| USER | bigint(20) | NO | MUL | NULL |
BUYER_INFO
| Field | Type | Null | Key | Default |
| id | bigint(20) | NO | PRI | NULL |
| purchase | bigint(20) | NO | UNI | NULL |
| document | varchar(14) | YES | MUL | NULL |
我不确定这是在StackOverflow上还是在这里,但是我已经阅读了帮助中心,它提到了query-performance
在这里是足够的。考虑到我在StackOverflow上研究这个问题时已经经历了几十个问题,而且没有发现任何有帮助的地方,我认为这可能是正确的地方。
我已经试过了
1-外部因素:传统的关键生产代码库,它构建SQL需要进行更大的更改才能将其实现为一个联合。
编辑:解决一些评论
只要数据检索正确,包括使用UNION的查询,这两个查询都能很好地工作。
另外,UNION查询对于我们的目的来说已经足够快了。
我宁愿避免它的唯一原因是,它需要对生产代码库进行更多的更改才能开始工作。(这里的查询经过了极大的净化和过度简化。)
(这就是为什么标题上写着without UNION
)
如果这是唯一明智的方法,那么我们会去做它,但我不明白为什么添加一个“或”的表现如此之多,我认为可能有什么东西,我忽视了。
如果我们将第一个查询分解为两个,则每个查询运行时间为2,5秒。但是使用OR操作符将它变成一个单一的查询,突然,它需要11分钟。
我希望能更好地理解为什么会这样,如果有可能的话。
发布于 2019-12-10 20:11:09
如果您从一个联合的结果中选择,那么您将能够快速过滤您正在寻找的结果,并且只需要有一个where子句。
SELECT info.id
FROM
(SELECT
purchase.id
FROM
purchase
LEFT OUTER JOIN user ON purchase.buyer = user.id
LEFT OUTER JOIN user_documents ON user.id = user_documents.user
UNION ALL
SELECT
purchase.id
FROM
purchase
LEFT OUTER JOIN buyer_info ON purchase.id = buyer_info.purchase) info
WHERE info.document = '123'
发布于 2019-12-12 21:24:05
您可以将WHERE谓词推入联接中,并检查至少有一个联接匹配:
SELECT purchase.id
FROM purchase
LEFT JOIN user
on purchase.buyer = user.id
LEFT JOIN user_documents
on user.id = user_documents.user
and user_documents.value = '123'
LEFT JOIN buyer_info
on purchase.id = buyer_info.purchase
and buyer_info.document = '123'
WHERE COALESCE(user_documents.value, buyer_info.document) IS NOT NULL
我以为documents.value应该是user_documents.value。
https://dba.stackexchange.com/questions/255340
复制相似问题