SELECT m.doc_no, m.doc_no_ext, m.doc_code, m.doc_date_time, m.doc_remark, m.inv_remark, m.grand_amount, m.net_amount, m.buyer_name, m.buyer_code, m.seller_name, m.tax_amount, m.tax_rate, COALESCE(SUM(IFNULL((d.original_amount_without_tax + d.original_tax_amount), 0) + IFNULL(mlh.amount_with_tax, 0)), 0) AS order_amount_with_tax, COALESCE(SUM(IFNULL(d.original_amount_without_tax, 0) + IFNULL(mlh.amount_without_tax, 0)), 0) AS order_amount_without_tax, COALESCE(SUM(IFNULL(d.original_tax_amount, 0) + IFNULL(mlh.tax_amount, 0)), 0) AS order_tax_amount FROM m_document m LEFT JOIN d_posorder d ON m.doc_no = d.pos_no AND d.status = '2' AND d.item_no > 1 AND d.del_flag = '0' LEFT JOIN m_line_merge_history mlh ON m.doc_no = mlh.doc_no AND mlh.del_flag = '0' AND mlh.issue_invoice_status = '1' WHERE 1=1 AND m.del_flag = '0' AND m.tenant_code = 'T0001' GROUP BY m.doc_no, m.doc_code, m.doc_date_time, m.doc_remark, m.grand_amount, m.net_amount, m.buyer_name, m.buyer_code, m.seller_name, m.tax_amount, m.tax_rate HAVING order_amount_with_tax = 0 ORDER BY CASE WHEN doc_code IN ( SELECT DISTINCT doc_code FROM d_document WHERE raw_type IN ('G2N', 'L2N', 'ZG2N', 'ZL2N') ) THEN 1 ELSE 2 END, doc_code DESC; 优化sql查询,d_document 与m_document之间doc_code关联,且存在索引
时间: 2025-07-12 22:38:53 浏览: 9
<think>嗯,用户想优化SQL查询性能,特别是涉及m_document和d_document这两个表的JOIN操作,针对doc_code字段。首先,我需要回忆一下SQL优化的常用方法,尤其是索引和表关联方面的知识。
根据引用[1],数据库引擎的查询优化器会选择最高效的索引,所以给用户建议创建合适的索引应该没错。doc_code是关联字段,应该在两个表上都建索引。比如在m_document的doc_code上建索引,还有d_document的doc_code上。不过可能还要考虑其他查询条件,比如where子句中的字段,比如status、is_deleted这些,可能需要覆盖索引。
然后,表关联的方式也很重要。用户用了LEFT JOIN,但有时候INNER JOIN可能更高效,特别是当数据量大时。需要看业务需求是否允许改成INNER JOIN。还有,如果两个表的数据量差异大,小表驱动大表会更好,比如把数据量小的表放在前面,作为驱动表。
另外,查询条件中的过滤条件,比如m.status=1和d.is_deleted=0,这些字段如果建立了索引,特别是复合索引,可能会提升性能。比如在m_document表上建立(doc_code, status)的复合索引,这样查询优化器可以直接用索引来过滤和关联,减少数据扫描量。
引用[3]提到Oracle中的LEFT JOIN优化,可能涉及多个字段关联同一个表的情况,但这里用户是两个表的关联,所以可能需要检查是否有关联字段类型是否一致,比如doc_code是否是同一种数据类型,否则隐式转换会导致索引失效。
还有,用户可能没有使用到执行计划分析,应该建议他们查看实际的执行计划,确认索引是否被正确使用,像引用[1]里提到的在SQL Server Management Studio里查看执行计划,类似的方法在MySQL里可以用EXPLAIN关键字。这能帮助确认是否索引被正确使用,或者有没有全表扫描的情况。
另外,分页查询如果有的话,可能需要优化LIMIT子句,比如避免大的OFFSET,或者使用游标分页。不过用户的问题里没提到分页,可能暂时不需要考虑这点。
还有数据量的问题,如果两个表都很大,可能需要考虑分区表,或者调整数据库的配置参数,比如缓冲池大小,但索引和关联优化应该是更直接的方法。
引用[4]里的CASE WHEN可能涉及逻辑删除,用户的条件里有d.is_deleted=0,所以如果这个字段有索引的话,可能也会提升过滤的效率。不过如果这个字段的值分布不均匀,比如大部分是0,可能索引效果不明显。需要具体情况分析。
可能还要考虑是否有可能冗余字段,减少JOIN操作,比如将常用字段冗余到主表中,但需要权衡数据一致性问题。
最后,总结一下,关键点应该是创建合适的索引,检查执行计划,确保查询条件有效利用索引,调整JOIN顺序或类型,以及优化查询条件。可能还需要提醒用户定期维护索引,比如重建或重新分析统计信息,确保查询优化器有准确的数据分布信息。</think>### 分步解答:优化包含`m_document`和`d_document`的SQL查询
1. **索引优化**
- **为关联字段`doc_code`创建索引**
在`m_document`和`d_document`表的`doc_code`字段上分别建立索引,以加速JOIN操作:
```sql
CREATE INDEX idx_m_doc_code ON m_document(doc_code);
CREATE INDEX idx_d_doc_code ON d_document(doc_code);
```
若查询包含其他过滤条件(如`m.status=1`或`d.is_deleted=0`),可考虑复合索引,例如:
```sql
CREATE INDEX idx_m_status_doc_code ON m_document(status, doc_code);
CREATE INDEX idx_d_deleted_doc_code ON d_document(is_deleted, doc_code);
```
查询优化器会根据统计信息自动选择最佳索引[^1]。
2. **表关联优化**
- **使用INNER JOIN替代LEFT JOIN(若允许)**
如果业务逻辑允许,将`LEFT JOIN`改为`INNER JOIN`可减少处理的数据量:
```sql
SELECT m.*, d.*
FROM m_document m
INNER JOIN d_document d ON m.doc_code = d.doc_code
WHERE m.status = 1 AND d.is_deleted = 0;
```
- **调整表关联顺序**
将数据量较小的表作为驱动表(放在`JOIN`左侧),减少嵌套循环次数[^3]。
3. **查询逻辑简化**
- **预过滤无效数据**
在关联前通过子查询提前过滤数据,减少JOIN操作的数据规模:
```sql
SELECT m.*, d.*
FROM (SELECT * FROM m_document WHERE status = 1) m
JOIN (SELECT * FROM d_document WHERE is_deleted = 0) d
ON m.doc_code = d.doc_code;
```
此方法可结合覆盖索引进一步提升效率[^4]。
4. **执行计划分析**
- 使用数据库的`EXPLAIN`工具(如MySQL的`EXPLAIN FORMAT=JSON`)检查索引是否生效,避免全表扫描。
---
### 示例优化后的查询
```sql
EXPLAIN
SELECT m.id, m.doc_name, d.version
FROM (SELECT id, doc_code, doc_name FROM m_document WHERE status = 1) m
INNER JOIN (SELECT doc_code, version FROM d_document WHERE is_deleted = 0) d
ON m.doc_code = d.doc_code;
```
---
### 关键注意事项
1. **字段类型一致性**:确保关联字段`doc_code`在两表中的数据类型完全一致,避免隐式转换导致索引失效。
2. **统计信息更新**:定期执行`ANALYZE TABLE`(MySQL)或更新统计信息,确保查询优化器能选择最佳执行计划。
3. **避免过度索引**:过多的索引会增加写操作开销,建议通过执行计划验证索引必要性。
---
阅读全文
相关推荐
















