I do both object oriented programming and (mostly transactional, but some OLAP) database design, and for my circumstances, there are a lot of recurring themes (at least with OLTP).
Practicing 3nf normalization helps me to practice some variant of the single responsibility principle. A table should represent a concept in your system - and concepts should relate to one another such that they attempt to mimick reality; for instance, if I'm building a system where a Customer can have 0 or many Activities, then I create a Customer Table, and an Activity Table. The activity table has a foreign key relationship to the Customer table. When I'm building stored procedures, I would make sure to use an outer join to join Customer and activity because the business requirement that a Customer can have 0 activities.
I also watch out for opportunities for extensibility by using bridge (link) tables. For instance, if I were trying to represent a business rule where a book could have an unlimited (variable) number of authors, I would create a Book Table, an Author table, and a bridge/link table that has foreign key references to both Book and Author.
Also, I use surrogate keys on all tables (typically auto-incrementing identity columns, but perhaps Guids - the tradeoff with guids in code is that they take up more memory space than a simple integer), and I avoid relying on natural keys for my lookups (except with Bridge/Link Tables). By default, I also create indexes on common foreign key columns, and review stored procedures/system queries from time-to-time to optimize indexing strategies. Another indexing strategy I use is to look for places in my code where I build a collection based on a search column, and add appropriate indexes to search columns.