0

我正在更新现有系统,需要坚持使用一些已使用的代码。每个 main_id 在表 n 中可能没有或有很多记录。main 中大约有 40k 条记录,n 中大约有 330k 条记录。

我只需要从 main 中选择过去 6 个月内没有 n.date 的记录。

不幸的是,我尝试过的每一种方式都非常缓慢。

main.main_id
main.field1
main.field2
main.field3

n.n_id
n.main_id
n.date
n.field1
n.field2
n.field3

查询的形式为

SELECT distinct(main.main_id) FROM main LEFT JOIN...

我已经尝试将子查询放置在各种地方,还有视图、临时表、添加索引,到目前为止,还没有任何东西使它接近合理的速度。

不幸的是,到目前为止,我还没有一份我尝试过的事情的清单,因为我希望我能让它发挥作用,所以没有记下它们,现在已经很晚了!

我怀疑我是否直接从 n 运行查询。表它可能会快很多,但这需要大量重写。查询中还有很多其他元素,但它在两秒钟内完成,表已加入,但没有这个。

这可能是最简单的——通常是更多的 WHERE 子句和 JOIN。

EXPLAIN 
SELECT distinct(`main`.`main_id`),`morefields`,`morefields2`
FROM main LEFT JOIN anothertable ON anothertable    anothertable.a_n = main.a 
LEFT JOIN anothertable2 ON anothertable2.g_n = main.CG 
LEFT JOIN anothertable3 ON anothertable3.t_n = main.t 
LEFT JOIN (SELECT max(DateTS) as note_date, main_id FROM n GROUP BY main_id) n_sub ON main.main_id=n_sub.main_id
WHERE main.deleted = '0' 
AND n_sub.note_date < DATE_SUB(now(), INTERVAL 6 MONTH)
ORDER BY main.morefields ASC LIMIT 0, 30;
+----+-------------+-------------+--------+---------------+---------+---------+----------------------------+--------+----------------------------------------------+
| id | select_type | table       | type   | possible_keys | key     | key_len | ref                        | rows   | Extra                                        |
+----+-------------+-------------+--------+---------------+---------+---------+----------------------------+--------+----------------------------------------------+
|  1 | PRIMARY     | <derived2>  | ALL    | NULL          | NULL    | NULL    | NULL                       |  40324 | Using where; Using temporary; Using filesort |
|  1 | PRIMARY     | main    | eq_ref | PRIMARY       | PRIMARY | 4       | n_sub.cust_no          |      1 | Using where                                  |
|  1 | PRIMARY     | anothertable       | eq_ref | PRIMARY       | PRIMARY | 4       | db.maij.area          |      1 |                                              |
|  1 | PRIMARY     | anothertable2 | eq_ref | PRIMARY       | PRIMARY | 4       | db.main.CG |      1 |                                              |
|  1 | PRIMARY     | anothertable3  | eq_ref | PRIMARY       | PRIMARY | 4       | db.main.t          |      1 |                                              |
|  2 | DERIVED     | n  | index  | NULL          | main_id | 4       | NULL                       | 285961 |                                              |
+----+-------------+-------------+--------+---------------+---------+---------+----------------------------+--------+----------------------------------------------+
6 rows in set (30.25 sec)
4

2 回答 2

0

基于此:

+----+-------------+-------------+--------+---------------+---------+---------+--------------+--------+----------------------------------------------+
| id | select_type | table       | type   | possible_keys | key     | key_len | ref          | rows   | Extra                                        |
+----+-------------+-------------+--------+---------------+---------+---------+--------------+--------+----------------------------------------------+
|  1 | PRIMARY     |<derived2>   | ALL    | NULL          | NULL    | NULL    | NULL         |  40324 | Using where; Using temporary; Using filesort |
|  1 | PRIMARY     |main         | eq_ref | PRIMARY       | PRIMARY | 4       | n_sub.cust_no|      1 | Using where                                  |
|  1 | PRIMARY     |anothertable | eq_ref | PRIMARY       | PRIMARY | 4       | db.maij.area |      1 |                                              |
|  1 | PRIMARY     |anothertable2| eq_ref | PRIMARY       | PRIMARY | 4       | db.main.CG   |      1 |                                              |
|  1 | PRIMARY     |anothertable3| eq_ref | PRIMARY       | PRIMARY | 4       | db.main.t    |      1 |                                              |
|  2 | DERIVED     |n            | index  | NULL          | main_id | 4       | NULL         | 285961 |                                              |
+----+-------------+-------------+--------+---------------+---------+---------+--------------+--------+----------------------------------------------+

...在我看来,您的索引有问题。例如,第一行表示它正在扫描 40,324 行完整的数据。更糟糕的是,看起来没有使用索引(key列),因为您的查询(possible_keys)中没有指定索引。

试试这个,或者类似的东西(除非我弄错了),但是在对你的实际数据库进行任何更改之前,一定要在数据库的备份副本上尝试它:

ALTER TABLE `main` ADD INDEX ( `main_id` )

编辑:

如果这没有帮助,我的下一个建议是尝试更改此行:

LEFT JOIN (SELECT max(DateTS) as note_date, main_id FROM n GROUP BY main_id) n_sub ON main.main_id=n_sub.main_id

对于这样的事情:

LEFT JOIN (SELECT max(DateTS) as note_date, main_id FROM n GROUP BY main_id) n_sub ON main.main_id=n_sub.main_id AND n_sub.note_date < DATE_SUB(now(), INTERVAL 6 MONTH)

这应该允许您完全删除此行:

AND n_sub.note_date < DATE_SUB(now(), INTERVAL 6 MONTH)

另一种可能性是尝试这样做:

SELECT distinct(`main`.`main_id`),`morefields`,`morefields2`
FROM main
-- Maybe change the next line to an INNER JOIN..?
LEFT JOIN n ON main.main_id = n.main_id
LEFT JOIN anothertable ON anothertable.a_n = main.a 
LEFT JOIN anothertable2 ON anothertable2.g_n = main.CG 
LEFT JOIN anothertable3 ON anothertable3.t_n = main.t 
WHERE main.deleted = '0'
GROUP BY main.main_id HAVING MAX(n.DateTS) < DATE_SUB(NOW(), INTERVAL 6 MONTH)
ORDER BY main.morefields ASC LIMIT 0, 30;
于 2013-09-30T06:29:14.430 回答
0

您应该能够根据在过去 6 个月内查找 FOR 活动的左连接来完整且简单地获取过去 6 个月内没有日期记录的 ID 列表,并为该连接的 NULL 应用 WHERE 子句。

SELECT 
      m.main_id,
      m.a,
      m.CG,
      m.t,
      m.morefields,
      m.morefields2,
   from
      main m
         left join n
            ON m.main_id = n.main_id
            and n.note_date > date_sub( now(), interval 6 month )
   where
          m.deleted = '0'
      AND n.main_id is null
   order by 
      m.morefields asc
   limit
      0, 30

现在,您还有其他连接,您可能也需要这些连接中的字段。如果是这样,我将包装上述内容并将其用作连接基础......我使用别名“PQ”来识别连接其余部分的“PreQuery”。

select 
      PQ.*,
      A_T1.SomeField(s),
      A_T2.SomeField(s),
      A_T3.SomeField(s)
   from 
      ( entire first query ) as PQ
         left join anothertable A_T1
            on PQ.a = A_T1.a_n
         left join anothertable2 A_T2
            on PQ.CG = A_T2.g_n
         left join anothertable2 A_T3
            on PQ.CG = A_T3.t

由于内部查询应用了 30 的限制,我们不需要再次重新应用限制(除非“另一个”表会导致一些笛卡尔结果并为每个主 ID 生成更多记录。)

为了明显隐藏实际数据/上下文,我只是猜测您真正加入的实际列。

于 2013-09-30T02:05:44.890 回答