编写更好的SQL

时间:2017-02-02 00:45:55

标签: mysql sql

我在这里遇到的问题非常缓慢。部分问题可能是子查询中的tableA与其他表相比具有相当大的大小。

表格结构

*-------------------*------------------*-------------------*
|     ID_TABLE      |    DATA_TABLE    |  DATA_TABLE_EXT   |
*-------------------*------------------*-------------------*
| id              n<|>1 id           1<|>n owner_id        |
| foreign_id        |   owner_id       |   information     |
| foreign_id_source |   date_field     |   ...             |
| ...               |  ...             |                   |
*-------------------*------------------*-------------------*

QUERY

SELECT ID_TABLE.foreign_id_source, count(ID_TABLE.id) as count 
FROM DATA_TABLE
LEFT JOIN ID_TABLE ON DATA_TABLE.id = ID_TABLE.id
WHERE DATA_TABLE.owner_id = 'some_id'
AND DATA_TABLE.date_field > 'some_date'
AND DATA_TABLE.id IN (
                SELECT DATA_TABLE_EXT.owner_id FROM DATA_TABLE_EXT
                JOIN DATA_TABLE ON DATA_TABLE_EXT.owner_id = DATA_TABLE.id
                WHERE DATA_TABLE.owner_id = 'some_id'
                GROUP BY DATA_TABLE.id
                HAVING SUM(ABS(DATA_TABLE_EXT.information)) <> 0
            )
GROUP BY ID_TABLE.foreign_id_source
ORDER BY count ASC

必修结果

*-------------------*-------------*
| foreign_id_source |    count    |
*-------------------*-------------*
|  source1          |     45      |
|  source2          |     10      |
|  ...              |             |
*-------------------*-------------*

DATA_TABLE中的每个ID在ID_TABLE中可能有多个记录。 DATA_TABLE中的许多记录可能具有相同的owner_id。

我正在寻找带有foreign_id_source的data_table中的记录数,该记录按foreign_id_source分组,其中记录位于'some_date'之后,并且它的DATA_TABLE_EXT记录在信息字段中的值都不是0。

如果没有创建索引或其他数据库操作,是否有办法在性能方面改进此查询?

欢迎任何其他建议。

2 个答案:

答案 0 :(得分:0)

经常将子查询移动到FROM会有所帮助:

SELECT ID_TABLE.foreign_id_source, count(DATA_TABLE.id) as count 
FROM ID_TABLE LEFT JOIN
     DATA_TABLE
     ON DATA_TABLE.id = ID_TABLE.id JOIN
     (SELECT DATA_TABLE.id
      FROM DATA_TABLE_EXT JOIN
           DATA_TABLE
           ON DATA_TABLE_EXT.owner_id = DATA_TABLE.id
      WHERE DATA_TABLE.owner_id = 'some_value'
      GROUP BY DATA_TABLE.id
      HAVING SUM(ABS(DATA_TABLE_EXT.information)) <> 0
     ) xx
     ON DATA_TABLE.id = xx.id
WHERE DATA_TABLE.owner_id = 'some_value' AND
      DATA_TABLE.date_field > 'some_date'
GROUP BY x.field1
ORDER BY count ASC;

然后,您可以考虑索引。这些是tableX(field2, fieldZ, field1, fieldX)tableI(field1),tableX(field2,field1,fieldB), and tableA(field1)`。

答案 1 :(得分:0)

重点是:SUM(ABS(DATA_TABLE_EXT.information)) <> 0只有在至少一个 DATA_TABLE_EXT.information非零时才能为真。所以我们不必sum()他们,我们只需要检查是否存在非零值。

[我不知道mysql是否足够智能来处理exists(),但理论上它更便宜,而且可以更快]

SELECT it.foreign_id_source, count(it.id) as count 
FROM DATA_TABLE dt
LEFT JOIN ID_TABLE it ON dt.id = it.id
WHERE dt.owner_id = 'some_id'
AND dt.date_field > 'some_date'
AND EXISTS ( 
        SELECT *
        FROM DATA_TABLE_EXT x
        JOIN DATA_TABLE dt2 ON x.owner_id = dt2.id
        WHERE x.id =dt.id
        AND dt2.owner_id = 'some_id'
        AND x.information <> 0
        )
GROUP BY it.foreign_id_source
ORDER BY count ASC
        ;