TAG系统
  tag在互联网应用里尤其多见,如果以传统的关系型数据库来设计有点不伦不类。我们以查找书的例子来看看redis在这方面的优势。
  关系型数据库的设计
  两张表,一张book的明细,一张tag表,表示每本的tag,一本书存在多个tag。
  mysql> select * from book;
  +------+-------------------------------+----------------+
  | id   | name                          | author         |
  +------+-------------------------------+----------------+
  |    1 | The Ruby Programming Language | Mark Pilgrim   |
  |    1 | Ruby on rail                  | David Flanagan |
  |    1 | Programming Erlang            | Joe Armstrong  |
  +------+-------------------------------+----------------+
  mysql> select * from tag;
  +---------+---------+
  | tagname | book_id |
  +---------+---------+
  | ruby    |       1 |
  | ruby    |       2 |
  | web     |       2 |
  | erlang  |       3 |
  +---------+---------+
  假如有如此需求,查找即是ruby又是web方面的书籍,如果以关系型数据库会怎么处理?
  select b.name, b.author from tag t1, tag t2, book b
  where t1.tagname = 'web' and t2.tagname = 'ruby' and t1.book_id = t2.book_id and b.id = t1.book_id
  tag表自关联2次再与book关联,这个sql还是比较复杂的,如果要求即ruby,但不是web方面的书籍呢?
  关系型数据其实并不太适合这些集合操作。
  redis的设计
  首先book的数据肯定要存储的,和上面一样。
  set book:1:name ”The Ruby Programming Language”
  Set book:2:name ”Ruby on rail”
  Set book:3:name ”Programming Erlang”
  set book:1:author ”Mark Pilgrim”
  Set book:2:author ”David Flanagan”
  Set book:3:author ”Joe Armstrong”
  tag表我们使用集合来存储数据,因为集合擅长求交集、并集
  sadd tag:ruby 1
  sadd tag:ruby 2
  sadd tag:web 2
  sadd tag:erlang 3
  那么,即属于ruby又属于web的书?
  inter_list = redis.sinter("tag.web", "tag:ruby")
  即属于ruby,但不属于web的书?
  inter_list = redis.sdiff("tag.ruby", "tag:web")
  属于ruby和属于web的书的合集?
  inter_list = redis.sunion("tag.ruby", "tag:web")
  简单到不行阿。
  从以上2个例子可以看出在某些场景里,关系型数据库是不太适合的,你可能能够设计出满足需求的系统,但总是感觉的怪怪的,有种生搬硬套的感觉。
  尤其登录系统这个例子,频繁的为业务建立索引。放在一个复杂的系统里,ddl(创建索引)有可能改变执行计划。导致其它的sql采用不同的执行计划,业务复杂的老系统,这个问题是很难预估的,sql千奇百怪。要求DBA对这个系统里所有的sql都了解,这点太难了。这个问题在oracle里尤其严重,每个DBA估计都碰到过。对于MySQL这类系统,ddl又不方便(虽然现在有online ddl的方法)。碰到大表,DBA凌晨爬起来在业务低峰期操作,这事我没少干过。而这种需求放到redis里很好处理,DBA仅仅对容量进行预估即可。
  未来的OLTP系统应该是kv和关系型的紧密结合。