9 ms·
A Missing Link in Postgres 11: Fast Column Creation with Defaults
- haney 8y agoThis is such a helpful addition that will help avoid so much downtime. Thank you to the Postgres contributors who made it possible.
- pilif 8y agoYou could certainly get the same effect without downtime prior to this. It just needed a few extra steps and some cooperation by the application: adding a null able column without default has always been instantaneous, so you would do that, then update all the rows that are missing the value. Finally, you add the default to the schema which will now be in the millisecond range because all/most rows have a default. And then you add the not null constraint which will also be in the ms range. You can do all of this in a transaction too because postgres' Schema modifications are transactional. This is how I have added countless columns with default values without downtime over the last few years.
- philliphaydon 8y agoThis is incredibly slow updating a billion rows to give a value to a new column as a blanket update will still be run as an implicit transaction. As does the constraint check before the default is applied. It can also use a LOT of disk space to do this as well.
- baq 8y agoWe always did that in batches about 1k to 10k rows. Takes a while but at least doesn't hammer the DB.
- gcbirzan 8y agoThe article does address this, it still has to check the DB for NULLs after you're done. Less downtime, but for huge tables it does take a significant amount of time.
- anarazel 8y agoThis optimization applies only for new columns with a stable default. Therefore a table scan is not required to check for NULLs, as either the default is NULL or not.
- gcbirzan 8y agoI was talking about the way to do it before. You could create a NULL-able column, add the default in batches, add the default/make it non-NULL-able. But, the last part took some time (not in the range of ms) for large tables.
- pilif 8y ago> But, the last part took some time (not in the range of ms) for large tables create a temporary index covering that column. Then it will be in the range of ms.
- pilif 8y agoyou can create a temporary conditional index on that table, then the check will be instantaneous. There is a `create index concurrently` that won't cause locks on the table. With this the re-check for nulls when adding the not null constraint will not take any time at all.
- gldalmaso 8y agoIf you are doing this, pay attention to the amount of dead tuples being accumulated over batches. We had to vaccuum analyze after each batch at least on one occasion where the index stopped being used by the query planner after a certain threshold of dead tuples. Even though there was no table lock, the performance hit made the application unusable from long running queries. The following query will show dead tuple count for the table: select tuple_count, dead_tuple_count from pgstattuple('table_name');
- haney 8y agoSorry, I should have clarified “accidentally downtime”. This doesn’t make anything new possibly, but will definitely eliminate a common way to shoot one’s self in the foot.
- mgkimsal 8y agowhoo doggy... https://github.com/postgres/postgres/commit/16828d5c0273b4fe5f10f42588005f16b415b2d8 https://github.com/postgres/postgres/commit/16828d5c0273b4fe... that was a lot of places to have to patch to make this happen!
- nerdponx 8y agoI think the most impressive part of a well-maintained software project, to me, is the ability of the maintainers to keep patches organized and maintain coherent and comprehensive change logs. I can barely manage this in my own four-man team.
- hvidgaard 8y agoThat is for better or worse, mostly down to someone actually spending the time to ensure that it happens.
- LoSboccacc 8y agoin a 4 man team the cost of maintaining program structure is enough to grind everything else to an halt. larger teams on larger projects have an incentive to keep the structure organized because without a clear codebase the project will grind to an halt and have the manpower to delegate maintenance tasks without killing the project speed.
- nerdponx 8y agoGood to know it's not "just me" then. I seem to have found a balance between "structure that appeals to the business side" and "not placing annoying restrictions on my teammates".
- deleted 8y ago[deleted]
- deleted 8y ago[deleted]
- philliphaydon 8y agoOh god this is the best feature of pg11 IMO.
- alangpierce 8y agoHmm, something I'm not understanding from the description of the implementation is how it handles this sequence of operations: 1.) Start with a nullable column with some existing rows with null values. 2.) Make the column required with default=100. Postgres now marks atthasmissing as true and attmissingval as 100. Rows will be lazy-populated to 100, but aren't immediately modified. 3.) Make the column nullable again. 4.) Add some new null values. 5.) Make the column required with default=200. At this point, the right behavior is that all originally-null rows from step #1 have value 100 and all rows added in step #4 have value 200, but that's not representable with the atthasmissing/attmissingval system. I guess maybe in steps 3 or 5 it needs to just bail out and do a full table rewrite? I was thinking through this problem a while ago and one idea I had was that you could version your schema and have each row remember what the schema version was when the row was created. Then you could lazy-populate any null value by looking up the next default value for the column chronologically in schema history. But I guess maybe that's complex enough or would hurt common-case perf enough that Postgres realistically isn't ever going to implement it.
- kdmytro 8y agoThe patch is about ALTER TABLE ADD COLUMN with non-null DEFAULT. Your step 1 does not have a default value so this patch will not affect the database behavior. Postgres will not do anything with atthasmissing or attmissingval on steps 2 and 5 because these are ALTER TABLE ALTER COLUMN DROP NOT NULL, which is out of scope of the discussed patch.
- alangpierce 8y agoI see, thanks! I guess I was interpreting it as "this is the new way that default values work in Postgres", but really it's only specific schema changes that are affected.
- colanderman 8y agoSetting a column NOT NULL with a default does not replace NULLs with the default value, it throws an error.
- 8y ago
- sudhirj 8y agoThis might have been the last case (for me at least) of having to choose a sub-standard database structure because of a limitation of the RDBMS. Now all migrations can add NOT NULL DEFAULT columns with impunity! Even on 100GB tables! Not sure exactly how much faster this will be, though.
- wiz21c 8y agoFTA : >>> and a gaping hole in Postgres’ operational story is filled Are there any other holes one should be aware of ? I'm looking forward to migrate a database with ~100 tables many of which having ~100 millions rows and lot's of FK to Postgresql... The operational side of things is what I know the least. Any pointers ?
- minxomat 8y agoLots of "Big Data" optimizations, like partitions becoming a first class feature, parallel queries and LLVM JIT on CPU-bound queries. HPE did an excellent technical, no marketing BS writeup on PG11[0]. I highly recommend everyone read this. [0] https://h50146.www5.hpe.com/products/software/oe/linux/mainstream/support/lcc/pdf/PostgreSQL_11_New_Features_beta1_en_20180525-1.pdf https://h50146.www5.hpe.com/products/software/oe/linux/mains...
- brightball 8y agoI'm about halfway through this now, but great read. Thank you for the link.
- snaky 8y agoWhile 100 millions rows is not exactly big number for PostgreSQL, so you might be well without partitioning, but still. > Despite the flexibility, this approach forces the planner to perform an exhaustive search and to check constraints on each partition to determine whether it should be present in the plan or not. Large amount of partitions may result in significant planning overhead. > The pg_pathman module features partition managing functions and optimized planning mechanism which utilizes knowledge of the partitions' structure. https://github.com/postgrespro/pg_pathman https://github.com/postgrespro/pg_pathman
- andruby 8y agoWe have tables with 5B rows and don't use partitioning (yet). I do recommend testing and optimising the vacuum settings for large or often updated tables.
- garyclarke27 8y agoAnother example of how impressive Postgres is, well done. I’m always amazed by how much faster Postgres gets with each release - unlike most other softwares that often get slower. Many parallel processing improvements in 11 should keep this up. Array and Composite Domains, Stored Procedures, Awesome Window functions even better framing / exlusion. Very few weakness vs Oracle now, apart from one glaring weakness - Materialized views - lack of auto incremental refresh, severely limits their usefulness. (SQL Server Mat views also fairly useless beacuse they have so many limitations). Would love to see - NOT IN Foreign key constraint - I would imagine this would be quite easy to implement on the back of existing IS In Foreign Keys, would be incredibly useful. Also why not increase the default identifier length from 63 to 127? I know can be done on first install(only then) so is a pain to do, I find long constraint names useful for understanding errors.
- iKevinShah 8y agoWhat I feel lacking in PG(though it can be easily managed by adding respective plugins) is the lack of unsigned int alike (from MySQL) AND UNIQUE columns be case-insensitive or an option of having case-insensitive unique columns while default be case-sensitive (As it is currently)
- bmdavi3 8y agoThere's no 'CASE INSENSITIVE' option for unique indexes, but you can unique on lower(my_column) to achieve the safe effect.
- iKevinShah 8y agoyes that is what I do currently as a workaround. I wished we had an option for case-insensitive unique indexes though..
- deleted 8y ago[deleted]
- 8y ago
- daigoba66 8y agoThis is cool. And another example of a feature that’s only available in Microsoft SQL Server Enterprise Edition ($$$), but effctively free in Postgres.
- grouseway 8y agoNo, another example of a feature that SQL server has had for a decade or more (in standard edition). Maybe you're thinking of online index creation? There are lots of reasons to criticize MSSQL (ridiculous cost, poor syntax/language extensions, awful text search, painful process for adhoc (non ETL) imports, etc...) but my decade old 2008 edition is still superior to PG in many ways. Why can't we have honest comparisons?
- rossdavidh 8y agoI have personally witnessed bogus schemas percolating up into the Django models.py, because of problems related to this. Good to know that Postgres11 fixes that. The fact that PG continues to improve in substantial ways even still, is pretty impressive for such a venerable piece of software. Well done.