我有这张桌子
attendance (4M rows at the moment, growing 1.2M per week):
-------------------------------------------------------------
| member_id | attendance_week | attendance_date | event_id |
------------------------------------------------------------
| INT (10) | TINYINT(2) | TIMESTAMP |TINYINT(3) |
-------------------------------------------------------------
attendance indeces:
--------------------------------------------------
| PRIMARY (attendance_week, member_id, event_id) |
| member_id (member_id) |
| event_id (event_id, attendance_week)
| total (attendance_week, event_id) |
--------------------------------------------------
members (400k rows at the moment growing 750 a week):
-------------------------
| member_id | dept_id |
-------------------------
| INT (10) |SMALLINT(5)|
-------------------------
member indeces:
-----------------------
| PRIMARY (member_id) |
|
-----------------------
事件是每周一次,这意味着您每周都会看到成对的member_id
和event_id
。
现在我必须为某个部门的每个事件生成一份报告current attendance
(即,如果该成员已经签到),以及他们至少 4 周的出席情况(即attended
/total
事件持续时间)
这是current_attendance
报告的一部分。我为一个部门获取所有成员,并LEFT JOIN
通过本周的活动获取NULL
缺勤:
SELECT
m.member_id AS id,
a.event_id AS attended
FROM
members AS m
LEFT JOIN
attendance AS a
ON
a.member_id = m.member_id AND
a.attendance_week = :week AND
a.event_id = :event
WHERE
m.dept_id = :dept
GROUP BY
m.member_id
这是attended
报告的一部分。:
SELECT
a.member_id,
COUNT(a.event_id)
FROM
attendance a
JOIN
members m
ON
a.member_id = m.member_id AND
m.dept_id = :dept
WHERE
a.attendance_week BETWEEN :start AND :end
GROUP BY
a.member_id
我可以通过简单地在第一个查询中再次使用LEFT JOIN
该表来合并这两个查询。attendance
最后是total
部分
SELECT
attendance_week,
COUNT(DISTINCT event_id)
FROM
attendance
WHERE
attendance_week BETWEEN :start AND :end
GROUP BY
attendance_week
这些是将针对这些表运行的主要查询。目前,查询平均运行150 - 200 毫秒(根据 phpMyAdmin),我认为这很慢。EXPLAIN
告诉我,我的 indeces 正在被使用。
所以这是我的问题:
- 有没有其他方法可以修改我的索引和查询以加快速度?
- 我假设 MySQL 有一个已编译语句的缓存。我不是在谈论结果缓存,想想 PHP 操作码与 HTML 缓存。我已经尝试过
SQL_NO_CACHE
,但我仍然得到相同的响应时间,并且query_cache_size
是 0。我可以发誓我看到 phpMyAdmin 以大约800 毫秒的速度报告了一次查询(这是不可接受的),但我现在没有得到它们。我如何衡量每次运行查询的真实速度? - 如果我将这些查询放在存储过程中,这些会更快吗?
- 对存储方法有什么想法吗?该数据库目前大小约为 400MB。一年后,我不知道,也许是 3GB?这是可扩展的吗?说到 DBA,我真的很陌生,我读过主从复制和分区,但我不知道这是否有好处。
如果您需要更多信息,请在下面发表评论。我会尽力提供。我确实尝试过独自完成这项工作,但考虑到大型数据库(我迄今为止最大的数据库)和高性能的需求,我真的需要一些建议:D
谢谢
编辑
我刚刚意识到我的逻辑有一个可怕的缺陷,新注册的会员会出现出勤率低的情况,因为第三次查询没有考虑注册日期。我的成员表中有一个 registration_date 列,有什么方法可以将该变量合并到查询中?或者一次合并所有三个查询?因为它们都返回依赖于每个用户的值。
编辑
我设法合并了前两个查询:
SELECT
m.member_id AS id,
a.event_id AS attended,
COUNT(b.event_id) AS total_attended
FROM
members AS m
LEFT JOIN
attendance AS a
ON
a.member_id = m.member_id AND
a.attendance_week = :week AND
a.event_id = :event
LEFT JOIN
attendance AS b
ON
b.member_id = m.member_id AND
b.attendance_week BETWEEN :start AND :end
WHERE
m.dept_id = :dept
GROUP BY
m.member_id
此查询在第一次运行时运行 925 毫秒,在后续请求中运行 15 毫秒。
这是上述查询的结果EXPLAIN
members table:
id: 1
select_type: SIMPLE
table: m
type: ref
possible_keys: dept_id
key: dept_id
key_len: 3
ref: const
rows: 88
Extra: Using where; Using index
attendance table 1 (for the boolean attended part):
id: 1
select_type: SIMPLE
table: a
type: eq_ref
possible_keys: PRIMARY,member_id,event_id,total
key: PRIMARY
key_len: 6
ref: const,arms_db.m.member_id,const
rows: 1
Extra: Using index
attendance table 2 (for the total attendanded part):
id: 1
select_type: SIMPLE
table: b
type: ref
possible_keys: PRIMARY,member_id,total
key: member_id
key_len: 4
ref: arms_db.m.member_id
rows: 5
Extra: Using index
最后EXPLAIN
一个查询:
id: 1
select_type: SIMPLE
table: attendance
type: range
possible_keys: PRIMARY,toral
key: total
key_len: 2
ref: NULL
rows: 9
Extra: Using where; Using index for groub-by