我有这个表的MySQL索引用于特定查询
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
再次-ing第一查询attendance
表合并这两个查询。
最后的total
部分
SELECT
attendance_week,
COUNT(DISTINCT event_id)
FROM
attendance
WHERE
attendance_week BETWEEN :start AND :end
GROUP BY
attendance_week
这些是将这些表上运行的主要查询。在这一刻,查询运行的平均值为150 - 200ms(根据phpMyAdmin),我认为这很慢。 EXPLAIN
告诉我,我的单位使用正在使用。
因此,这里是我的问题:
- 有没有办法,我可以修改我的indeces和查询,使这个更快的任何其他方式?
- 我假设MySQL有编译语句的缓存。我不是在谈论结果缓存,认为PHP操作码vs HTML缓存。我已经尝试
SQL_NO_CACHE
,我仍然得到相同的响应时间,query_cache_size
是0.我可以发誓,我看到phpMyAdmin在800ms报告查询一次(这是不可接受的),但我现在没有得到它们。如何在每次运行时测量查询的真实速度? - 如果我把这些查询放在存储过程中,这些会更快吗?
- 存储方法的任何想法?该数据库目前大小约为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
此查询925ms运行在后续请求第一次运行和15ms的。
这是结果上述查询的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
什么是MySQL服务器版本? – 2012-08-10 01:53:24
5.5.25a社区服务器 – 2012-08-10 02:34:03
表是MyISAM还是InnoDB? – 2012-08-10 09:08:24