MySQL在同一张表上两次联接给出一半的结果

时间:2019-04-20 01:34:36

标签: python mysql python-3.x

我有2个表并进行联接查询,但事实是,在主表中我有2列ID需要用第二个表中的全名替换的id,这就是为什么我在同一个表上运行两次查询的原因。问题是它大约没有记录的一半,如果我更改联接的位置,则会出现后一半。标识符2列中的数据类似于:(271,272),(272,271)

    query = "SELECT * FROM (SELECT * from transactions {2} LIMIT {3}, {4}) as transactions " \
            "LEFT JOIN (SELECT account_number as dr, account_name as dr_n, acc_id, company_id, deleted FROM tb_accounts) as tb1 ON tb1.acc_id = transactions.dr_acc " \
            "LEFT JOIN (SELECT account_number as cr, account_name as cr_n, acc_id, company_id, deleted FROM tb_accounts) as tb2 ON tb2.acc_id = transactions.cr_acc " \
            "LEFT JOIN (SELECT document as doc_name, doc_id, company_id, deleted FROM documents ORDER BY documents.date DESC) as doc1 ON doc1.doc_id = transactions.document " \
            "and doc1.company_id = {0} and doc1.deleted = 0 " \
            "WHERE tb1.company_id = {0} and tb1.deleted = 0 and " \
            "tb2.company_id = {0} and tb2.deleted = 0 and " \
            "transactions.company_id = {0} and {1} transactions.deleted = 0".format(company_id, filter, sort, sn, en)

1 个答案:

答案 0 :(得分:0)

您的查询看起来很复杂,并且可以通过生成要在联接中使用的临时表来相当慢地执行。

我也不认为您在那里需要LEFT JOIN。相反,它应该是JOININNER JOIN)。

导致问题的原因是LIMIT运算符放在顶部。

我建议使用以下查询(看看如何将其放入Python中-在数据库客户端中复制/粘贴和测试要方便得多)

query = """
    SELECT *
    FROM transactions as transactions
    JOIN tb_accounts as tb1
    ON tb1.acc_id = transactions.dr_acc AND tb1.deleted = 0 AND tb1.company_id = {0}
    JOIN tb_accounts as tb2
    ON tb2.acc_id = transactions.cr_acc AND tb2.deleted = 0 AND tb2.company_id = {0}
    JOIN documents as doc1
    ON doc1.doc_id = transactions.document
        AND doc1.company_id = {0}
        AND doc1.deleted = 0
    WHERE transactions.company_id = {0}
      AND transactions.deleted = 0
      {1}
    {2}
    LIMIT {3}, {4}
""".format(company_id, filter, sort, sn, en)

为优化上述查询的速度,以下索引将很有用:

CREATE INDEX idx_del_comp_acc
ON tb_accounts (deleted, company_id, acc_id);

CREATE INDEX idx_del_comp_doc
ON documents (deleted, company_id, doc_id);

CREATE INDEX idx_del_comp_dr_acc
ON transactions (deleted, company_id, dr_acc);

CREATE INDEX idx_del_comp_cr_acc
ON transactions (deleted, company_id, cr_acc);

按照上述顺序在索引中包含列很重要。

同样重要的是,运行查询时还要满足哪些其他条件,以及要运行哪些其他查询。在这种情况下,您可以添加更多索引或重新设计上面的索引。

在查询之前使用命令EXPLAIN,以查看服务器将如何运行它以及将使用什么索引(如果有)。

但是请记住,添加索引会增加INSERT和UPDATE请求的时间。通常,索引比插入慢一点的好处多。