复杂sql查询如何选择索引

问题描述 投票:0回答:1

我正在处理一个复杂的 SQL 查询,其中涉及多个联接、子查询、分组和排序。主要目标是提高该查询的性能,特别是通过选择正确的索引。虽然我对如何为更简单的查询进行索引选择有一个大致的了解,但我不确定如何确定像这样的查询的不同部分的优先级。我应该首先关注优化子查询、分组或 ORDER BY 子句吗?此外,我不确定是否存在冗余过滤器,或者是否可以优化某些连接以获得更好的性能。

SELECT
    S.id AS salesperson_id,
    S.name AS salesperson_name,
    S.mobile AS salesperson_phone_number,
    B.name AS brand_name,
    ci.id AS collection_invoice_id,
    ci.invoice_no AS invoice_number,
    ci.status as status,
    ci.invoice_date AS invoice_date,
    DATE_FORMAT(ci.collection_date,'%d-%m-%Y') AS collection_date,
    DAYOFWEEK(ci.collection_date) AS collection_weekday_number,
    ci.invoice_amount AS invoice_value,
    ci.invoice_assigned_by AS invoice_assigned_by,
    ci.invoice_updated_by AS invoice_updated_by,
    ci.verified_by_cashier_id AS verified_by_cashier_id,
    ci.verified_by_segregator_id AS verified_by_segregator_id,
    ci.invoice_verification_status AS invoice_verification_status,
    DATEDIFF(CURDATE(), DATE(ci.invoice_date)) AS invoice_age,
    ci.invoice_amount AS invoice_value,
    (SELECT COALESCE( SUM(amount), 0) from payments WHERE collection_invoice_id = ci.id) AS collected_amount,
    ci.initial_outstanding_amount AS outstanding_amount,
    ci.current_outstanding_amount AS new_outstanding,
    ci.fc_id AS collection_fc_id,
    ci.brand_id AS collection_brand_id,
    B.id AS brand_id,
    B.name AS brand_name,
    B.code AS brand_code,
    ci.store_id AS collection_store_id,
    store.id AS store_id,
    store.name AS store_name,
    store.code AS store_code,
    ci.salesman_id AS collection_salesman_id,
    ci.handover_old_salesman_id  AS old_collection_salesman_id,
    co.beat_name as beat_name,
    (SELECT name FROM Salesmen WHERE id = ci.handover_old_salesman_id) AS old_collection_salesperson_name,
    (SELECT mobile FROM Salesmen WHERE id = ci.handover_old_salesman_id) AS old_collection_salesperson_phone_number
FROM table1 AS ci
JOIN Brands AS B ON ci.brand_id = B.id
JOIN Stores AS store ON ci.store_id = store.id
JOIN Salesmen AS S ON ci.salesman_id = S.id
LEFT JOIN Orders AS Orde ON ci.order_id = Orde.id
LEFT JOIN Allocations AS alcn ON Orde.allocation_id = alcn.id
JOIN ChampOutstandingInvoices co on ci.invoice_no = co.invoice_no and co.fc_id = ci.fc_id
WHERE ci.brand_id IN (35,32,24,21,5,4,3,1,37) 
    AND ci.fc_id IN (1) AND ci.salesman_id != 0 
    AND (ci.collection_date >= DATE_ADD(DATE(CURDATE()), INTERVAL -3 DAY) AND ci.collection_date <= DATE_ADD(DATE(CURDATE()), INTERVAL 3 DAY)  ) 
    AND (ci.salesman_id = 16552 ) 
    AND ci.fc_id IN (1) 
    AND ci.brand_id IN (21) 
    AND (DAYOFWEEK(ci.collection_date) IN ( 4 )) 
    AND (ci.brand_id IN ( 21 )) 
    AND ci.id IN (
        SELECT max(id) AS id
        FROM collection_invoices AS ci
        WHERE ci.brand_id IN (35,32,24,21,5,4,3,1,37) 
            AND ci.fc_id IN (1) 
            AND ci.salesman_id != 0 
            AND (ci.collection_date >= DATE_ADD(DATE(CURDATE()), INTERVAL -3 DAY) 
            AND ci.collection_date <= DATE_ADD(DATE(CURDATE()), INTERVAL 3 DAY)  ) 
            AND (ci.salesman_id = 16552 ) 
            AND ci.fc_id IN (1) 
            AND ci.brand_id IN (21) 
            AND (DAYOFWEEK(ci.collection_date) IN ( 4 )) 
            AND (ci.brand_id IN ( 21 ))
        GROUP BY invoice_no, fc_id, brand_id
        ) 
    AND ci.invoice_assigned_by IS NULL 
    AND ci.initial_outstanding_amount > 0 
    AND (Orde.status IN ('DL','PD') 
    AND alcn.return_status = 'Complete')  
ORDER BY ci.invoice_no ASC
limit 50 offset 0
sql mysql indexing greatest-n-per-group
1个回答
0
投票

请不要重复使用相同的别名(

ci
);它使查询难以解析。

这些可能对于 that 查询(和一些类似的查询)有用

table1:               INDEX(salesman_id, collection_date)
table1:               INDEX(brand_id,    collection_date)
collection_invoices:  INDEX(salesman_id, collection_date) 
collection_invoices:  INDEX(brand_id,    collection_date)

很明显,您的查询可能有很多变化。 没有好的解决办法。 我喜欢使用 2 列或 3 列复合索引,其中第一列使用

=
进行测试,并且可以选择将最后一列作为范围。

这看起来像是一个分组最大问题,但我不确定。 我添加了标签。

有关为查询选择索引的更多讨论:Index Cookbook

© www.soinside.com 2019 - 2024. All rights reserved.