PostgreSQL Features You May Not Have Tried but Should
pgdash.io
pgdash.io
For example, we can have the function `full_name(person)` that returns the concatenation of `person.first_name` and `person.last_name`, and we can do `SELECT p.full_name FROM person p`. I think it's pretty neat.
The first database software that I was paid to work on was UniVerse. At the time it was owned by, I believe, VMark Software, but it changed hands a few times and is now part of the Rocket U2[0] family. It has an equivalent feature, which was very heavily used, called I-Descriptors.
An I-Descriptor is an entry in a file's data dictionary that contained code to execute to calculate the value. You could generate a full name out of the firstname/lastname fields, perform conditional logic (e.g., return a specific address based on a preferred address field), etc. You could also call subroutines, where you had the full power of the BASIC language available.
One of the interesting things I did was created a field which would perform geolocation based on the postal code portion of the address. It would split out the postal code, check a cache file for the data, call a web service to retrieve the data and cache it (if it wasn't in the cache already, otherwise it would just return the cached value), and return the results. Everything needed was built in to the database, it was just a matter of coding it. The best part was that it became just another thing you could do in the query language - answering the question "list all active clients in this geographic area" became just another query.
In PostgREST, we take advantage of this behavior to generate queries without the need for extra code to differentiate between a field or "virtual field", we call these "computed columns" though https://postgrest.org/en/v5.0/api.html#computed-columns.
[0] https://www.postgresql.org/docs/10/static/datatype-json.html
> SELECT a.id, JSONB_AGG(b.id) AS b_id FROM a, b GROUP BY a.id
[0] Do not get me wrong - if you can ignore the price tag, MSSQL is a great database engine. It has never given me any trouble I have not asked for, and it has some very nice features of its own (e.g. the Service Broker).
SQL Server 2005 included SQLOS, bypassing the OS for direct memory and disk access that did wonders for performance. Parallel query execution in 2010 further cemented performance gains.
If only it had simple upserts, array types and proper json support, small details that make a big difference.
This has been my experience as well, though I haven't used it since SQL 2012. I dreadfully miss SQL Server Management Studio (SSMS), it is BY FAR the best IDE/GUI for a database I've ever come across.
One problem is that all those fancy features are released before they are done and never completed afterwards. Thus, Postgres is a mess of special cases that prevent things from working well together. Here are just a few examples I can list off the top of my head:
* You can't make arrays of domain types (domain types are a way to constrain the allowed values of some underlying more-primitive type)
* You can't parse JSON into a composite that has composites as any of its field types
* You can't do update..returning or insert...returning as a subquery and have to fall back to CTEs
* Composites are not allowed to contain instances of themselves within any of their fields
* Table inheritance doesn't work well with uniqueness constraints
Additionally, both the text and binary data exchange formats are completely unspecified with the binary format being completely undocumented and the text format being woefully underdocumented. The text format is also just really really messy and the results that you get back from the server are very irregular... It's pretty much impossible to write a Postgres driver that is anything other than a pile of hacks produced by reading the code and guessing. Pretty much none of them properly handle the more completed cases (most just punt on composites, for example).
Anyway: Postgres has a lot of wonderful tech in it that would take many, many years to duplicate and I would pick it from the field of actually-available RDBMSes every time but... it's still deeply terrible.
All that is to say: Postgres very much feels (to me) like tech from the awful, edge-casey past that is simply so useful and so hard to replicate that we are stuck with it!
If you want a general purpose language as your database engine, you'll likely end up with something more like MongoDB where for any moderately complex query you'll end up hand-writing a single static query plan for everything.
This is probably why people seem less fussed about some of the asymmetries you identify in RDBMSs. Different philosophies.
Do you mean recursive type definitions? Or? Who does allow that? And what would you use it for in an SQL context? Please elaborate, I'm curious what you are getting at here.
> Table inheritance doesn't work well with uniqueness constraints
This got somewhat better in postgresql 11 (beta1 is available now) in that unique works for partitioned tables. I don't know if that also includes inherited tables, they are similar but not the same. Partitioned tables are the case most people are interested in anyway.
> These deficiencies will probably be fixed in some future release, but in the meantime considerable care is needed in deciding whether inheritance is useful for your application.
https://www.postgresql.org/docs/current/static/ddl-inherit.h...
For what I'm doing I got away with having insert/delete triggers on child tables that mirror their identity/type to a 'types' table. Also enforced through check constraints and FKs
On my blog, I have a lot of articles about the game series Borderlands. If you type "Borderlands" into the search box, it will find them, but if you type "border lands", it won't. Same with "starcraft" and "star craft", etc.
It looks like I will have to implement trigrams on top of full text search to fix:
[0] https://www.postgresql.org/docs/11/static/textsearch-diction...
https://www.postgresql.org/docs/11/static/ddl-partitioning.h...
Can you be more specific about why you shouldn't use it like this? I've used it for similar cases and it's seemed to work fine. You have to declare some foreign keys / constraints that you shouldn't really need to, but it's not really any harder than creating the "child" tables from scratch anyway.
I use the table inheritance to manage common fields in the database more easily instead of having to define a separate table and reference it
For example the base model, which includes fields for external objects the row might reference and certain option fields or a ratings table that allows an object to include all the necessary fields for rating a product. This way I can also copy a lot of code since the structs on the other side also can share a lot of code and data.
(I still frequently run into people who work a lot with SQL that don't use CTEs, though less than before :)
SELECT *
FROM ( ... ) AS results
may have a completely different query plan than a query like WITH results AS ( ... )
SELECT *
FROM results
This may or may not be desirable, and is important to be aware of.- data checksuming (can be enabled in initdb)
- extending the database in C (mostly adding various functions, that would be hard and slow to implement in SQL, but I've also been able to write functions that generate datasets on the fly that are loaded from a custom server over a unix socket)
- writing ECPG clients https://www.postgresql.org/docs/current/static/ecpg.html
I wrote a long answer on Quora on that topic:
https://www.quora.com/Amazon-redshift-uses-Actians-ParaAccel...
Arrays scale as you'd expect, i.e. even if it's allowed, I don't recommend 1MM values in an array because some/many of the aforementioned features aren't tested to scale. AFAIK array operations are single threaded and not vectorized or parallelized.
The only drawback for me is that you can't have arrays of foreign keys. (You could of course just store an array of the key values, but without the integrity checks).
If your data is more complex then they tend to break down a bit, but at that point you should probably be looking at a joining table or other construct that supports foreign keys and such.
A caveat: I used it only for small arrays (about 10 elements maximum.) I don't know how the ORM/driver/database combination would perform with thousands or more elements.
Also, triggers seem pretty controversial in the discussions I've been privy too, most devs seem to hate them. Any positive experiences with them?
Triggers themselves, beside the typical use cases of logging and notifying channels, I find useful for non-disruptive schema upgrades. You can redirect updates, or fill in non-trivial default values, using them. (Rules could probably fill the same role.)
Also writeable views.
Whereas in an RDBMS, there is no "code" attached to a relation; and the data is explicitly exposed. Inheritance starts to look more like the typical pattern of structure with common fields at the top level, and disjoint fields inside a discriminated union. You can mirror this with RDBMS composition (foreign keys), but you lose the ability to enforce even basic structural constraints (tricks like mutually-referential foreign keys notwithstanding).
Having said all that I think it's better to have a firm understanding and a feel for RDBMS operations and development techniques and that you can produce more solid work if you have that understanding. I think if you have that understanding (and actually have an appropriate problem for a RDBMS solution) there are roles for triggers/procedures/functions in the database... just understand where the boundaries are and delineate clear responsibilities to the various pieces of the stack (that's the hard part and the part in which many fail). I also think that if you are a developer needing to make use of an RDBMS and don't have a solid understanding of your RDBMS of choice, you're going to screw up more than just anything to do with triggers/functions/procedures/etc. This is why I always approach projects where ORMs are important with caution. ORMs are just a tool, true, but often times they are also the rug under which the database can be swept... or to put it another way, a framework for building technical debt. (Yeah, yeah, not always, but frequently).
As for PostgreSQL table inheritance... just say no. You cannot overcome the object/relational impedance with that feature and you end up compromising too much of why you might want a RDBMS in the first place. I've only seen it used well twice; one of those cases being table partitioning and that is, from a user perspective, becoming much less necessary with new features in PostgreSQL. PostgreSQL is an Object Relational Database Management System, but I think you have to consider the object part of that as primarily being useful inside the database itself: it can be useful in more sophisticated uses of the database itself, especially if you are writing functions/triggers, but isn't a great tool in my experience to map to OO systems outside of the database. I have found it much clearer from an information architectural perspective and easier to maintain data integrity using standard RDBMS modeling techniques (with the exception of maintaining certain unstructured data as JSON blobs).
Not only did it solve my bottle neck issues it just made it very apparent that there are a lot of things ORM do that make everything harder. They have their place but working with the DB/SQL/Triggers/Views/Mat Views/ ... improved my applications greatly.
Now years later anytime i am working with a new developer i always stress that they at least learn the basics.
For example, lets say I have an accounting system with a general ledger structured with a header table (row per journal entry) and a child detail table (row per GL Account with either debited or credited amount) and the idea that journal entries need to be "posted" to be considered part of the business transactional history. I may have a business rule that says: I can never post a journal entry that isn't balanced (debits must equal credits). It is always invalid to have a posted and unbalanced journal entry.
Assuming that the posting status is recorded in the header table, I may well write a trigger on the header table which, on updating the posted status of the header record to posted, checks that all of the detail lines sum up to a balanced journal entry and aborts the transaction if that rule is not met. This is a de facto encapsulation of business logic, but one important to data integrity. Sure I can also use a stored procedure, but I may want to have a trigger to be involved because of the difference between an active and passive application of the rule: a stored procedure for posting requires an explicit call... but just doing an UPDATE against the table won't call my stored procedure (or other application code for posting) whereas a trigger forces the issue. In many of the enterprise environments that I work in, the main accounting application is not the only way data gets into the database so I can't rely on those explicit calls to always be made to enforce the rules... the database is the final authority and forcing it there can also eliminate a class of issues. I may well have my trigger call my posting stored procedure if that procedure were written the right way...
Yes, I'm taking other issues like performance as granted as well, but I mostly wanted to show another aspect to consideration related to trigger use. [edit] Perhaps a more fine tuned approach is to say business logic which doesn't change data, but ensures rules should be met or the transaction is cancelled, helps with the side-effect issue you cite.
[couple edits for grammar/clarity]
Some years back I worked at a place that went deep on triggers and stored procedures and it totally put me off using either (sql server). There was a lot of opaque behaviour that was hard to debug and performance was terrible.
A friend is a great dB developer (one of the top on stack exchange) and when I asked him about triggers he said that he doesn’t use them for updating data, ever, unless it’s someone else’s totally broken schema and he has to dig himself out of a hole.
On the other hand, he loves stores procs and pretty much every interaction he lets apps have with the dB run through stored procs. What are your thoughts on how heavily you should lean on stored procs?
https://webcache.googleusercontent.com/search?q=cache:kQC5xW...