Use What Works: Prefixing Database Tables With 'tbl'
thomaslarock.com
thomaslarock.com
It is more common to have qualification for objects that aren't collections of rows, like sequences, constraints, and indexes. These are qualifications like "fk_", "pk_", "uniq_", etc. and they serve the purpose of being able to distinguish between "relations", which are the primary API of the database, and "supporting" constructs. These names need to be distinguished from table names as well as from each other and with the exception of sequences are also not present in SQL statements, only DDL.
Consider why none of the other names in relational databases are prefixed as to their type. We all use functions like "current_timestamp", "count", keywords like "CAST", fixed system tables and views like "pg_catalog". Why aren't these named "fnCurrentTimestamp", "fnCount", "keywordCAST", "tblPgCatalog" ?
object_name_mv
object_name_vw
I can only assume that at some point the view was non-performant for user-facing application and was turned into a snapshot.In general, I'm a fan of suffixing views with '_vw' to basically be a red flag saying "there's another query behind me."
So which is it? "All the tables" or "58%".
What you're trying to say is that inconsistency lights up the amateurs lights.
A practice whose relationship to tibbling is mostly cosmetic. Dim and fact are prefixes that are used to indicate additional semantics about the table's purpose that can't be determined by inspecting the object itself - in this case, whether the table represents a dimension or a fact.
Tibbling, on the other hand, doesn't do much more than harm maintainability in the long run. Consider what happens if, say, you ever need to split a table into two different ones. You probably don't want to have to go and rewrite all the queries that referenced that old table. No problem, just create a view that joins the two new tables and give it the same name as the old table. Now everything that referenced the old table will still work fine.
Except if you tibbled the table name. If you did that, then you still need to go track down and modify every single object that references the table. That, or you'll be resolved to having a view whose name starts with 'tbl' in your database. In which case your tibbling scheme has been torpedoed, because the presence of erroneously prefixed objects means you can no longer trust any of the prefixes.
At some point you might need to denormalize, replacing a view with a materialized view. Now you either need to change every instance in your code, or you need to have a table prefixed with "vw". (Similar troubles apply if you replace a table with a view.)
The entire purpose of views is that from the perspective of the client, it doesn't matter whether it's a table or a view.
I agree, the client shouldn't care about the data being a table or a view. But as a DBA, if I need to quickly find a solution to a problem, the use of a prefix can be a benefit.
There are costs and risks for all design choices. If you are working with a system that is growing and prone to the need of denormalizing frequently then perhaps using a prefix isn't the right choice.
But not every system has that issue. I see more cases these days of smaller databases...think "one database per customer" type of architecture. Denormalization isn't an issue often, and prefixes seem to work just fine.
If you work with a growing codebase that slowly falls into the (popular) antipattern of DatabaseAsIntegrationPoint, you will end up with dozens of programs spread out over multiple repositories all interacting with some shared tables (not ideal, but it happens).
If you named your tables something like "posts" then I _guarantee_ that if you grepped your entire repository for "posts" that you are going to find an awful lot of false positives in variables and class names. OTOH if you named it "tblposts" then it's far more likely to be a globally unique string identifier.
Why would you need to grep the codebase for a table name you ask?
* prerequisite to a non-additive table ALTER that might have unintended side effects
* prerequisite to trying to undo the carnage of DatabaseAsIntegrationPoint
You shouldn't have to do that in a well-factored appliation, because you're using stored procedures instead of inline SQL.
SELECT COUNT(*) FROM tblposts
Either way gets you some degree of surface area management. Procedures have some added benefit--it's a lot easier to inspect the flow of data when everything is routed through procedure calls. It's a lot easier to put that flow in context when you have a procedure name as a label, provided that your procedures implement a batchful interface.
This approach only makes sense in one of two situations:
1. Ivory Tower DBAs run your company and tell developers "no" at every turn. (sad)
2. Your engineering team makes changing queries hard because they can't hire any developers who know anything about your underlying database platform internals. (also sad)
1. Maintainability. It's necessary to put your SQL on the server if you want to keep it well factored. Just like for any other language, oft-repeated bits of SQL code should be factored out into separate procedures and functions. If you're relying on inline SQL, you're forced to choose between habitually violating the DRY principle or resorting to an unmaintainable mishmash of server-side and client-side queries.
2. Testability. The good unit testing frameworks for SQL code are written in SQL, and designed to be used from an SQL development environment (i.e., the database). And just like for any other language, your SQL code should be covered by good tests.
There are plenty of tools out there to help with deployment if it's causing difficulties for you. I recommend using them if that's what it takes for you to be comfortable with the platform.
So most recently, we had an app that started off with direct table access via an ORM. Once the data access paths stabilized somewhat, I started replacing them with stored procedures. Those stored procedures gradually coalesced to form an API. The ORM-like functionality is still there, if need be, but the stored procedures now provide a contract, much like a service.
In retrospect, I'm not sure the ORM was even that useful. Besides encouraging certain bad habits on the consumer side (eg, most instances of lazy loading), its one more level of indirection to grapple with. Why not drop down to the database and write your implementation there? It can be tested right there and then, and directly in terms of the data flow: input -> output.
I remember debating with our datawarehouse designer whether our tables should be singularly-named or plural. Also if the primary key should be TablenameID or just ID.
In the end it doesn't matter. The only thing that materially impacts productivity is maintaining consistent conventions. Take it from someone currently working on a database with three different object prefix styles, key naming and data access methods (ORM, stored procedures and argh dynamic SQL).
So for a table 'user' you would have: user_id, user_name, user_password, etc. Some tables would have ridiculous long column names.
So what is this good for? First off, joins. If you had a 'post' table and a foreign key back to user_id, the naming scheme was: post_userid. So a join would be: "select from post inner join user on user_id = post_userid". There is no need to alias either table. Also, if both tables have the same field, say both have a 'note' field, it is clear which note you are accessing and there are no ambiguous issues (since one table is post_note and the other is user_note).
I've been through all of these naming schemas over the years (including the OP's tbl prefix and your table_ column prefix) and honestly they don't help. At best they disambiguate a corner case and make for a lot more typing than is needed. At worst you end up with things out of sync and you have a view named tblFoo with a column named post_blah because you don't want to mess up something that was coded a year ago and needs to keep working.
Keep things simple, format your queries, be consistent and all will work about as well as it's going to work. SQL is ugly.
On the other hand, it bakes the schema into every single column reference, and that makes schema changes more costly--either you cruft up your database with now-misnamed columns, or you fix all references, or you avoid changes in the first place, and the business drifts further and further from the database model.
My compromise position at places that do use column prefixes has been, column prefixes on base tables, views and/or stored procedures for client access, and no prefixes exposed to the client.
He's talking about naming things (one of the two hard problems), where what the thing is becomes more readable to him with the prefix on the name.
At the end of the day, however, consistency is key. For example, you used a capital letter to distinguish the start of a word, making it easier for me to understand what you were saying.
What's interesting about the "use what works" mantra invoked here is it's not saying who this should work for. A database is a resource that's typically shared between multiple parties, and enforcing one somewhat arbitrary rule for the convenience of one party to the detriment of another party doesn't sound very amicable.
At best it's the obnoxious curry code special.
The tools have been failing us. Using a prefix is a way to get around those failings.
Let's say you have identified a performance problem on a single page of a web application that lists results from a query.
Let's say you look at the code and see a complex query.
What do you do?
You use the equivalent of EXPLAIN on your DB.
It should be pretty clear at that point what objects you are dealing with.
The point of a view is that it should be interchangeable with a table logically. There are many cases I've been involved in where a view was used to either temporarily address a performance issue or address a data migration need.
If you have a naming standard that requires objects to be named a certain way, you're going to have to do a code push along with a database change that would otherwise only require a database change. That's a lot of extra testing and a lot of extra risk.
Either that or you are going to temporarily break your own rules just for that one thing. But now guess what, you've created an even bigger problem because you have trained everyone to not look at the EXPLAIN plan and instead rely on the names of the objects, and so now they'll be really confused because you've temporarily made a view "look" like a table.
In practice, this is a solution to a non-issue. YMMV.
If I'm looking at a join I need to make sure that the data is how I'd expect- is it 1..1, 1..many? If I don't have a good understanding of the object and the data it contains, I don't care if it has a prefix, I'm going to dig deeper. If I dig deeper I'm going to remember what that object represents and I won't need a prefix in the future.
So what exactly is the use case of the "tbl" prefix? Are you skimming over unknown objects just because they have a prefix? I don't see any upside.
...and ditched the "rockstar" bit.
For database code, executing in the database (ie, stored procedures and the like), table prefixing does make the code more searchable, and reduces the amount of context one needs to grok a single block of code. When you need to refactor, you can quickly find all references.
But as a public face to clients, I find that tbl-prefixing exposes too much implementation detail. Tables and views are both relations, and there's a continuum from physical relation to virtual relation. If I use the same naming convention for both, I can keep my public API constant while iterating on the physical schema. This is very useful to me. Consequently, within the API, I try to keep views simple, and write them to provide table-like performance.
2) typically there is no single order table. Most systems will have order_summary / order_details / order_items / order_packages . Think of handling a single order that has multiple products each of multiple quantities. And to complicate, fulfillment of product quantity requires multiple warehouses / shipments.
3) you can have a table called order, you just have to ensure to escape it properly, either double quotes or square brackets. Similarly table names can have spaces in them.