【发布时间】:2013-12-04 19:38:07
【问题描述】:
情况如下:
我有几张表格(如下所述),用于跟踪公寓楼中的居民、他们的单元号以及他们最后一次“被看到”的时间(我们有很多有健康问题的老年人,因此检查他们很重要每 2 天左右;有时它们会死在这里,这就是我们知道如何检查它们的方式。
“检查”的限制条件是必须在过去 48 小时内看到它们;如果没有,查询应该拉他们的记录。以下是我正在使用的表定义:
“人”表,存储居民信息:
MariaDB [olin2]> describe people;
+-------------+-------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+-------------+------+-----+-------------------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| fname | varchar(32) | NO | MUL | NULL | |
| lname | varchar(32) | NO | | NULL | |
| dob | date | YES | | NULL | |
| license_no | varchar(24) | NO | | NULL | |
| date_added | timestamp | NO | | CURRENT_TIMESTAMP | |
| status | varchar(8) | NO | | Allow | |
| license_exp | date | YES | | NULL | |
+-------------+-------------+------+-----+-------------------+----------------+
“单位”表,其中存储单位编号(人们切换单位,所以我不希望他们在“人”表中):
MariaDB [olin2]> describe units;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| number | varchar(3) | NO | MUL | NULL | |
| resident | int(11) | NO | | NULL | |
| type | varchar(16) | NO | | NULL | |
+----------+-------------+------+-----+---------+----------------+
以及存储“支票”的“健康”表(居民的身份证号码、何时以及由谁看到等):
MariaDB [olin2]> describe wellness;
+--------------+-------------+------+-----+-------------------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------+-------------+------+-----+-------------------+----------------+
| wellness_id | int(11) | NO | PRI | NULL | auto_increment |
| people_id | int(11) | NO | | NULL | |
| time_checked | timestamp | NO | | CURRENT_TIMESTAMP | |
| check_type | varchar(1) | NO | | NULL | |
| username | varchar(16) | NO | | NULL | |
| return_date | timestamp | YES | | NULL | |
+--------------+-------------+------+-----+-------------------+----------------+
“健康”表中的“return_date”字段是针对居民离开超过2天时,显示时不会包含在结果中(实际上会包含在查询结果中) ,但我使用 PHP 将其过滤掉)。
这是我一直在使用的查询...它运行了几个星期,但随着添加的记录越来越多,它变得明显变慢(现在返回结果需要 3.5 秒):
select p.id, w.time_checked, w.username, w.return_date
from people p
left join units u on p.id = u.resident
left join wellness w on p.id = w.people_id
left join wellness as w2 on w.people_id = w2.people_id
and w.time_checked < w2.time_checked
where w2.people_id is null
and w.time_checked < (now() - interval 48 hour)
order by u.number
我知道我的问题是连接,但我不知道如何在没有它们的情况下获得所需的结果和/或如何优化此查询以加快速度...这是结果示例(如果需要) :
+----+---------------------+----------+---------------------+
| id | time_checked | username | return_date |
+----+---------------------+----------+---------------------+
| 8 | 2013-12-01 11:00:13 | tluce | 0000-00-00 00:00:00 |
+----+---------------------+----------+---------------------+
1 row in set (3.44 sec)
所以,在这个结果集中,居民 8 已经有 3 天没有出现了……结果是正确的,但 3.44 秒对于我的用户来说是不可接受的,必须等待。
关于如何改进这一点有什么想法吗?
编辑(更多信息):
我意识到更新每个人的健康条目会更容易、更快捷;但是我喜欢手头有这些数据,因为我从中生成图表以显示 A) 我们最常看到特定居民的时间和 B) 工作人员最常检查人员的时间(也就是 - 谁在做他们的工作,谁不是)
我确实使用了索引,这是我的查询中 EXPLAIN 的结果:
+------+-------------+-------+--------+---------------+---------+---------+----------------- -+------+--------------------------------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+------+-------------+-------+--------+---------------+---------+---------+----------------- -+------+--------------------------------------------------------------------+
| 1 | SIMPLE | u | ALL | NULL | NULL | NULL | NULL | 107 | Using temporary; Using filesort |
| 1 | SIMPLE | p | eq_ref | PRIMARY,idx | PRIMARY | 4 | olin2.u.resident | 1 | Using where |
| 1 | SIMPLE | w | ALL | NULL | NULL | NULL | NULL | 7074 | Using where; Using join buffer (flat, BNL join) |
| 1 | SIMPLE | w2 | ALL | NULL | NULL | NULL | NULL | 7074 | Using where; Not exists; Using join buffer (incremental, BNL join) |
+------+-------------+-------+--------+---------------+---------+---------+----------------- -+------+--------------------------------------------------------------------+
people表中的索引:id, fname, lname, license_no
养生桌:wellness_id
单位表:id, number
【问题讨论】:
-
你能在这个查询上运行 EXPLAIN 吗?
-
Sam D:请查看我的编辑以获取您要求的信息。
-
在可能的键下,每个字段为 NULL 表示未使用索引。因此您可以将索引添加到您用于连接的字段。例如units.residents。你可以对 wellness.people_id 做同样的事情
-
真正做到了这一点的人,现在查询在 0.26 秒内运行......非常感谢!添加该评论作为答案,我会接受!
-
刚刚添加。谢谢
标签: php mysql sql performance