避免多列主键。当努力编写高效的查询时,多列主键将会导致查询语句很难理解,并且很难修改。我们可以使用一个整型的主键,或者一个多列的唯一约束,再或者一些单列的索引来取代多列主键。
5. 与外键一致命名主键和外键有许多种风格。我们建议诸位使用的是最为普遍的风格,即对于任意的表格foo,将foo中的主键命名为id,将所有的外键命名为foo_id。
另一种风格是使用全局统一的主键名。在这种风格下,表foo的主键称为foo_id,而所有的外键也称为foo_id。不过无论使用哪种风格,使用缩写的话(比如将users表缩写为uid),总是会造成困扰或名称冲突,所以应该避免使用缩写。
而且,无论你选用了什么风格,都要坚持下去。不要在某些地方使用uid,而又在其他地方使用user_id或者users_fk。
select*
from packages
joinusers on users.user_id = packages.uid
-- vs
select*
from packages
joinusers on users.id= packages.user_id
--or
select*
from packages
joinusersusing(user_id)
除此之外还要留意外键并不显式匹配一张表的情况。一个名为owner_id的列可能是users表的一个外键,当然也可能不是。因此如果有必要的话,请将作为外键的列命名为user_id或者owner_user_id。
6. 将日期时间存储为各种日期时间类型不要使用Unix的时间戳或者字符串来存储日期,而是要将它们转换为各种日期时间类型。虽然SQL的日期计算函数并不是最棒的,但是调用这些函数来处理时间戳总比自己来处理要简单。在查询时,我们需要为每一个涉及到从timestamp到datetime类型的转换的查询调用SQL的日期函数
selectdate(from_unixtime(created_at))
from packages
-- vs
selectdate(created_at)
from packages
不要将年、月、日分别存储到不同的列中。因为这样会导致每个有关时间序列的查询都更加难写,而且也会在使用这张表的日期信息时给大多数的SQL初学者造成障碍。
selectdate(created_year ||'-'
|| created_month ||'-'
|| created_day)
-- vs
selectdate(created_at)
7. 总是使用UTC使用时区而不是UTC将导致无穷无尽的问题。好的工具(包括我们的Periscope)拥有你所需要的从UTC转换为你所在时区数据的所有功能。在Periscope中,简单地加个:pst就可以将UTC转换为太平洋时间。
select[created_at:pst], email_address
fromusers
应该将数据库的时区设为UTC,并且所有datetime的列都应该是剥离时区后的类型(如,无时区的timestamp)。
如果你的数据库的时区不是UTC,或者你的数据库混合了UTC和非UTC时间日期,那么时间序列的分析查询将会变得更加困难。
8.单一的真相源一块数据应该只有单一的真相源(Source of Truth)。视图和汇总(Rollup)本身应该有所标示。这样做的话,数据的消费者就会知道他们使用的数据和原生真相之间的区别。
select*
from daily_usage_rollup
另一方面,将诸如user_id、user_id_old或者user_id_v2的遗留列都保留的话,只会带来无尽的困扰。因此请确保在日常维护中会进行删除废弃的表格和不再使用的字段的工作。
9.优先使用没有JSON列的表格请不要使用列过多的表。如果一张表有超过几十个列并且其中一些是以序列命名(例如,answer1、answer2、answer3)的话,那么马上你就会感到不好过了。