【原創】日誌表設計一例分析

關於關係表的設計歸根結底有兩個方面。

第一,就是完全按照範式理論去設計,一般來說達到第三範式就可以了,或者你可以劃分的更細到達更上一層次。比如第四,第五,第六等等。這種設計有自己的可讀性很強,但是有一點,在檢索數據的時候增加了多張關係表來做關聯的開銷。

第二,就是在範式理論上適當的做些反範式,有的東西還是不要太剝離的好。(窄表以及寬表) 這點和軟件設計中的緊耦合鬆耦合理論一致。


下面我就以常用的LOG表來做下演示,其中有兩種表的實際,一種是窄表,一種是稍微寬一點的表。

窄表:log_ytt

mysql> show create table log_ytt;    
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table       | Create Table                                                                                                                                                             |
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| log_ytt | CREATE TABLE `log_ytt` (
  `ids` bigint(20) DEFAULT NULL,
  `log_time` datetime DEFAULT NULL,
  KEY `idx_u1` (`ids`,`log_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 | 
+-------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)


表記錄數

mysql>  select * from log_ytt where ids > '4875000001';                                                                                    +------------+---------------------+
| ids        | log_time            |
+------------+---------------------+
| 7110000001 | 2014-05-20 21:56:42 | 
| 6300000001 | 2014-05-20 21:56:42 | 
| 6750000001 | 2014-05-20 21:56:42 | 
| 5310000001 | 2014-05-20 21:56:42 | 
| 7200000001 | 2014-05-20 21:56:42 | 
| 7380000001 | 2014-05-20 21:56:42 | 
| 5760000001 | 2014-05-20 21:56:42 | 
| 6930000001 | 2014-05-20 21:56:42 | 
| 6660000001 | 2014-05-20 21:56:42 | 
| 5670000001 | 2014-05-20 21:56:42 | 
| 6210000001 | 2014-05-20 21:56:42 | 
| 5850000001 | 2014-05-20 21:56:42 | 
| 6570000001 | 2014-05-20 21:56:42 | 
| 5580000001 | 2014-05-20 21:56:42 | 
| 5130000001 | 2014-05-20 21:56:42 | 
| 7290000001 | 2014-05-20 21:56:42 | 
| 6390000001 | 2014-05-20 21:56:42 | 
| 5490000001 | 2014-05-20 21:56:42 | 
| 5220000001 | 2014-05-20 21:56:42 | 
| 7560000001 | 2014-05-20 21:56:42 | 
| 7470000001 | 2014-05-20 21:56:42 | 
| 7020000001 | 2014-05-20 21:56:42 | 
| 6840000001 | 2014-05-20 21:56:42 | 
| 6030000001 | 2014-05-20 21:56:42 | 
| 6480000001 | 2014-05-20 21:56:42 | 
| 7650000001 | 2014-05-20 21:56:42 | 
| 5940000001 | 2014-05-20 21:56:42 | 
| 6120000001 | 2014-05-20 21:56:42 | 
| 7740000001 | 2014-05-20 21:56:42 | 
| 5400000001 | 2014-05-20 21:56:42 | 
| 5760000001 | 2014-05-21 03:19:07 | 
| 6840000001 | 2014-05-21 03:19:17 | 
| 7020000001 | 2014-05-21 03:19:32 | 
| 7200000001 | 2014-05-21 03:19:45 | 
| 7110000001 | 2014-05-21 03:19:46 | 
| 7380000001 | 2014-05-21 03:19:48 | 
| 5670000001 | 2014-05-21 03:19:58 | 
| 6930000001 | 2014-05-21 03:19:59 | 
| 6030000001 | 2014-05-21 03:20:00 | 
| 5940000001 | 2014-05-21 03:20:00 | 
| 7290000001 | 2014-05-21 03:20:02 | 
| 6120000001 | 2014-05-21 03:20:09 | 
| 5850000001 | 2014-05-21 03:20:18 | 
| 5580000001 | 2014-05-21 03:20:24 | 
| 6480000001 | 2014-05-21 03:25:05 | 
| 6390000001 | 2014-05-21 03:25:37 | 
| 6210000001 | 2014-05-21 03:25:45 | 
| 7470000001 | 2014-05-21 03:26:14 | 
| 6750000001 | 2014-05-21 03:27:17 | 
| 5310000001 | 2014-05-21 03:27:33 | 
| 5130000001 | 2014-05-21 03:27:34 | 
| 6570000001 | 2014-05-21 03:27:34 | 
| 7560000001 | 2014-05-21 03:27:45 | 
| 5220000001 | 2014-05-21 03:27:45 | 
| 5400000001 | 2014-05-21 03:27:53 | 
| 5490000001 | 2014-05-21 03:27:55 | 
| 6660000001 | 2014-05-21 03:28:07 | 
| 6300000001 | 2014-05-21 03:28:13 | 
| 7740000001 | 2014-05-21 03:28:26 | 
| 7650000001 | 2014-05-21 03:28:37 | 
+------------+---------------------+
60 rows in set (0.00 sec)



接下來,我們要檢索所有IDS的平均時間。 有以下兩種方式:

第一, 對錶進行了兩次訪問,並且有GROUP BY 操作,不可取。

mysql> select sec_to_time(avg(timestampdiff(second,a.times,b.times)))  as 'running' 
    -> from 
    -> (select ids,min(log_time) as times from log_ytt where 1 group by ids ) as a,
    -> (select ids,max(log_time) as times from log_ytt where 1 group by ids) as b where a.ids = b.ids;
+---------------+
| running       |
+---------------+
| 05:27:08.8333 | 
+---------------+
1 row in set (0.00 sec)


第二,雖然對錶進行了最少的訪問,但是也有一次GROUP BY 操作。也沒辦法,表設計如此。

mysql> SELECT SEC_TO_TIME(AVG(times)) AS 'Running' FROM 
    -> (
    -> SELECT TIMESTAMPDIFF(SECOND,MIN(log_time),MAX(log_time)) AS times FROM log_ytt GROUP BY ids
    -> ) AS T;
+---------------+
| Running       |
+---------------+
| 05:27:08.8333 | 
+---------------+
1 row in set (0.00 sec)


寬表:log_ytt_horizontal.

mysql> show create table log_ytt_horizontal;
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table                  | Create Table                                                                                                                                                                                              |
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| log_ytt_horizontal | CREATE TABLE `log_ytt_horizontal` (
  `ids` bigint(20) NOT NULL,
  `start_time` datetime DEFAULT NULL,
  `end_time` datetime DEFAULT NULL,
  PRIMARY KEY (`ids`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 | 
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)


表記錄數:

mysql> select * from log_ytt_horizontal;
+------------+---------------------+---------------------+
| ids        | start_time          | end_time            |
+------------+---------------------+---------------------+
| 5130000001 | 2014-05-20 21:56:42 | 2014-05-21 03:27:34 | 
| 5220000001 | 2014-05-20 21:56:42 | 2014-05-21 03:27:45 | 
| 5310000001 | 2014-05-20 21:56:42 | 2014-05-21 03:27:33 | 
| 5400000001 | 2014-05-20 21:56:42 | 2014-05-21 03:27:53 | 
| 5490000001 | 2014-05-20 21:56:42 | 2014-05-21 03:27:55 | 
| 5580000001 | 2014-05-20 21:56:42 | 2014-05-21 03:20:24 | 
| 5670000001 | 2014-05-20 21:56:42 | 2014-05-21 03:19:58 | 
| 5760000001 | 2014-05-20 21:56:42 | 2014-05-21 03:19:07 | 
| 5850000001 | 2014-05-20 21:56:42 | 2014-05-21 03:20:18 | 
| 5940000001 | 2014-05-20 21:56:42 | 2014-05-21 03:20:00 | 
| 6030000001 | 2014-05-20 21:56:42 | 2014-05-21 03:20:00 | 
| 6120000001 | 2014-05-20 21:56:42 | 2014-05-21 03:20:09 | 
| 6210000001 | 2014-05-20 21:56:42 | 2014-05-21 03:25:45 | 
| 6300000001 | 2014-05-20 21:56:42 | 2014-05-21 03:28:13 | 
| 6390000001 | 2014-05-20 21:56:42 | 2014-05-21 03:25:37 | 
| 6480000001 | 2014-05-20 21:56:42 | 2014-05-21 03:25:05 | 
| 6570000001 | 2014-05-20 21:56:42 | 2014-05-21 03:27:34 | 
| 6660000001 | 2014-05-20 21:56:42 | 2014-05-21 03:28:07 | 
| 6750000001 | 2014-05-20 21:56:42 | 2014-05-21 03:27:17 | 
| 6840000001 | 2014-05-20 21:56:42 | 2014-05-21 03:19:17 | 
| 6930000001 | 2014-05-20 21:56:42 | 2014-05-21 03:19:59 | 
| 7020000001 | 2014-05-20 21:56:42 | 2014-05-21 03:19:32 | 
| 7110000001 | 2014-05-20 21:56:42 | 2014-05-21 03:19:46 | 
| 7200000001 | 2014-05-20 21:56:42 | 2014-05-21 03:19:45 | 
| 7290000001 | 2014-05-20 21:56:42 | 2014-05-21 03:20:02 | 
| 7380000001 | 2014-05-20 21:56:42 | 2014-05-21 03:19:48 | 
| 7470000001 | 2014-05-20 21:56:42 | 2014-05-21 03:26:14 | 
| 7560000001 | 2014-05-20 21:56:42 | 2014-05-21 03:27:45 | 
| 7650000001 | 2014-05-20 21:56:42 | 2014-05-21 03:28:37 | 
| 7740000001 | 2014-05-20 21:56:42 | 2014-05-21 03:28:26 | 
+------------+---------------------+---------------------+
30 rows in set (0.00 sec)


如果對這種稍微冗餘一些的表來進行查詢,那麼對錶的訪問以及CPU的資源佔用都達到了最低。

mysql> select sec_to_time(avg(timestampdiff(second,start_time,end_time))) as 'Running'  from log_ytt_horizontal;
+---------------+
| Running       |
+---------------+
| 05:27:08.8333 | 
+---------------+
1 row in set (0.00 sec)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章