我有两个mysql表a
和b
,一对多关系(b
实际上是a
之间多对多关系的链接表{1}}和其他一些表格:
mysql> DESCRIBE a;
+-------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+-------------------+-----------------------------+
| id | bigint(30) | NO | PRI | 0 | |
| date | timestamp | NO | MUL | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
+-------+--------------+------+-----+-------------------+-----------------------------+
2 rows in set (0.00 sec)
mysql> DESCRIBE b;
+-------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| a_id | bigint(30) | NO | PRI | 0 | |
| field | smallint(6) | NO | PRI | NULL | |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)
随着频繁插入新行,我需要知道最后一秒在表b
中插入了多少行。
我还需要区分b.field
大于,等于或小于0
的行({somedate}
是一秒前的时间):
SELECT count(*) FROM a INNER JOIN b ON a.id = b.a_id
WHERE a.date >= '{somedate}' AND b.field > 0
SELECT count(*) FROM a INNER JOIN b ON a.id = b.a_id
WHERE a.date >= '{somedate}' AND b.field = 0
SELECT count(*) FROM a INNER JOIN b ON a.id = b.a_id
WHERE a.date >= '{somedate}' AND b.field < 0
这三个查询花了大约5秒钟,所以我尝试通过将它们全部放在同一个查询中来优化它们:
SELECT sum(CASE WHEN b.field > 0 THEN 1 ELSE 0 END),
sum(CASE WHEN b.field = 0 THEN 1 ELSE 0 END),
sum(CASE WHEN b.field < 0 THEN 1 ELSE 0 END)
FROM a INNER JOIN b ON a.id = b.a_id
WHERE a.date >= '{somedate}'
但是,我不确定这是否有所改善。
我的性能问题仅仅是因为我对最后一秒发生的事情感兴趣,所以如果查询占用的时间超过一秒,这显然不是很有用。
如何改善这些查询的效果?最好不必修改表格。
更多信息:
mysql> SHOW CREATE TABLE a\G
*************************** 1. row ***************************
Table: a
Create Table: CREATE TABLE `a` (
`id` bigint(30) NOT NULL DEFAULT '0',
`date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`),
KEY `date_index` (`date`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)
mysql> SHOW CREATE TABLE b\G
*************************** 1. row ***************************
Table: b
Create Table: CREATE TABLE `b` (
`a_id` bigint(30) NOT NULL DEFAULT '0',
`field` smallint(6) NOT NULL,
PRIMARY KEY (`a_id`,`field`),
KEY `a_id_fk` (`a_id`),
KEY `field_fk` (`field`),
CONSTRAINT `a_id_fk` FOREIGN KEY (`a_id`) REFERENCES `a` (`id`),
CONSTRAINT `field_fk` FOREIGN KEY (`field`) REFERENCES `c` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
1 row in set (0.00 sec)
mysql> EXPLAIN SELECT count(*) FROM a INNER JOIN b ON a.id = b.a_id WHERE a.date >= '2014-10-15' AND b.field = 0;
+----+-------------+-------+--------+--------------------------+----------+---------+-----------------+-------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+--------------------------+----------+---------+-----------------+-------+-------------+
| 1 | SIMPLE | b | ref | PRIMARY,field_fk,a_id_fk | field_fk | 2 | const | 40698 | Using index |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 8 | database.b.a_id | 1 | Using where |
+----+-------------+-------+--------+--------------------------+----------+---------+-----------------+-------+-------------+
2 rows in set (0.00 sec)
mysql> EXPLAIN SELECT count(*) FROM a INNER JOIN b ON a.id = b.a_id WHERE a.date >= '2014-10-15' AND b.field > 0;
+----+-------------+-------+--------+--------------------------+----------+---------+-----------------+--------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+--------------------------+----------+---------+-----------------+--------+--------------------------+
| 1 | SIMPLE | b | range | PRIMARY,field_fk,a_id_fk | field_fk | 2 | NULL | 370846 | Using where; Using index |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 8 | database.b.a_id | 1 | Using where |
+----+-------------+-------+--------+--------------------------+----------+---------+-----------------+--------+--------------------------+
2 rows in set (0.00 sec)
mysql> EXPLAIN SELECT sum(CASE WHEN b.field > 0 THEN 1 ELSE 0 END), sum(CASE WHEN b.field = 0 THEN 1 ELSE 0 END), sum(CASE WHEN b.field < 0 THEN 1 ELSE 0 END) FROM a INNER JOIN b ON a.id = b.a_id WHERE a.date >= '2014-10-15';
+----+-------------+-------+--------+-----------------+----------+---------+-----------------+--------+-------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------+----------+---------+-----------------+--------+-------------+
| 1 | SIMPLE | b | index | PRIMARY,a_id_fk | field_fk | 2 | NULL | 741976 | Using index |
| 1 | SIMPLE | a | eq_ref | PRIMARY | PRIMARY | 8 | database.b.a_id | 1 | Using where |
+----+-------------+-------+--------+-----------------+----------+---------+-----------------+--------+-------------+
2 rows in set (0.00 sec)