使用复杂的SQL请求进行后期行查找

时间:2015-10-08 08:30:15

标签: mysql

我有一个可以过滤的列表(多个过滤器),分页并且原始生成的sql是:

SELECT 
    b0_.id AS id0,
    b0_.offset AS offset1,
    b0_.title AS title2,
    b0_.message AS message3,
    b0_.type AS type4,
    b0_.resolved_at AS resolved_at5,
    b0_.operationImport_id AS operationImport_id6
FROM
    bank_import_error b0_
        INNER JOIN
    bank_operation_import b1_ ON b0_.operationImport_id = b1_.id
        INNER JOIN
    bank_account b2_ ON b1_.account_id = b2_.id
WHERE
    b2_.company_id = 1
        AND (b1_.started_at LIKE '%03%'
        OR b0_.title LIKE '%03%'
        OR b2_.name LIKE '%03%'
        OR b0_.offset LIKE '%03%')
ORDER BY b1_.started_at ASC
LIMIT 10 OFFSET 70

此请求需要3,5到4分钟,因此我尝试应用"后期行查找"技术:

SELECT    b.id as id0,    b.offset as offset1,    b.title as title2,   b.message as message3,    b.type as type4,    b.resolved_at as resolver_at5,    b.operationImport_id as operationImport_id6 FROM 
    (SELECT 
        b0.id
    FROM
        (SELECT id, operationImport_id FROM bank_import_error WHERE title LIKE '%03%' OR offset LIKE '%03%') b0
    LEFT JOIN
        (SELECT id, account_id, started_at FROM bank_operation_import WHERE started_at LIKE '%03%') b1 ON b0.operationImport_id = b1.id
    LEFT JOIN
        (SELECT id from bank_account WHERE name like '%03%' AND company_id = 1) b2 ON b1.account_id = b2.id      ORDER BY B1.started_at ASC
    LIMIT 10 OFFSET 70 
    ) o INNER JOIN bank_import_error b on b.id = o.id

但是这第二个请求并没有给出相同的结果。订购问题?一个逻辑问题?我该怎么做才能解决这个问题?

环境:Mysql,InnoDB。 SQLFiddle:http://sqlfiddle.com/#!9/a4157/1/0 但是这些信息非常敏感,所以我暂时不把数据放在表格中。

1 个答案:

答案 0 :(得分:0)

后期行查找要求您编写一个有效的子查询,该子查询获取行子集的ID,并将其与查询的其余部分连接起来。

SELECT 
   b0_.id AS id0,
   b0_.offset AS offset1,
   b0_.title AS title2,
   b0_.message AS message3,
   b0_.type AS type4,
   b0_.resolved_at AS resolved_at5,
   b0_.operationImport_id AS operationImport_id6
FROM
   bank_import_error b0_
       INNER JOIN
   bank_operation_import b1_ ON b0_.operationImport_id = b1_.id
       INNER JOIN
   bank_account b2_ ON b1_.account_id = b2_.id
       INNER JOIN
   (SELECT id
    FROM bank_operation_import
    ORDER BY started_at ASC
    LIMIT 10 OFFSET 70) AS b3_ ON b1_.id = b3_.id
WHERE
   b2_.company_id = 1
       AND (b1_.started_at LIKE '%03%'
       OR b0_.title LIKE '%03%'
       OR b2_.name LIKE '%03%'
       OR b0_.offset LIKE '%03%')
ORDER BY b1_.started_at ASC

但是,这不会返回与原始查询相同的数据,因为您在之后过滤选择了有限的行。

我认为在你的查询中很好地利用后期行查找,因为你需要在分页之前进行过滤,而过滤是昂贵的部分(因为LIKE '%03%'可以'被索引)。