When you do a shrink-file on a data file, pages from the end of the file are moved to unused pages at the beginning of the file. That very effectively will cause many indexes to be "inverted", which results in segment sizes of "1" just as surely as if the index were 99% fragmented and the pages aren't just out of order... they may be entirely reversed.
The "root cause" you're looking for is the fact that you shrunk the database and it caused index inversion.
Then, the massive secondary cause came into play... you did index maintenance but, if you were looking for fragmentation, you missed all the heaps because they don't "fragment". They make forwarded rows instead and that means that you probably didn't rebuild the heaps that needed it.
The reason why your data inserts are probably taking so long is because you did index maintenance on indexes that have a default "0" Fill Factor. If they're prone to fragmenting, it's usually because of page splits and you just removed every last vestige of free space available in the index that was actually created by the act of page splitting but in a slower and more spread-out fashion before. Of course, some of your heaps are backwards and those need to have their "tables" rebuilt.
And that's all a bit of a catch 22 because you basically did a whole bunch of hole punching on the disk and your segment sizes are likely in the toilet even after rebuilds.
I don't know how much offline time you might have but here's what I'd do because you need to get rid of a lot of the "hole punching".
- Find the largest index . If you have the space, create a filegroup/file just a little bigger than the index. Do a CREATE INDEX WITH (DROP_EXISTING = ON) to move it to the new filegroup/file. The reason why we're doing this is to temporarily make some room to help get rid of the hole punching and to make it so that the rebuild doesn't take up 100% more room equal to the size of the heap/index. If you have the room to do this to an extra 1 to 4 of your largest indexes, it would be worthwhile.
- Disable as many non-unique non-clustered indexes as possible. This will also make a ton of room to help get rid of the hole punching. Don't disable any unique indexes or other indexes that are enforcing constraints unless you also want to rebuild all of your FKs and possibly some other nasty stuff. 😉
- Rebuild your heaps from smallest to largest.
- Rebuild your non-unique non-clustered indexes that have NOT been disabled. Rebuild them from smallest to largest.
- Rebuild your previously disabled non-clustered indexes from smallest to largest.
- Rebuild your clustered indexes from smallest to largest.
- Rebuild the largest index(es) you'd previously moved to a new filegroup/file to move it/them back to the primary file group from smallest to largest.
- Drop the now-empty new file and filegroup to return the disk space to the system.
- Disk space is pretty cheap... invest in some bigger disks.
Hopefully, after all that, your segment sizes will be a who lot larger. You should probably look into which indexes could make use of a Fill Factor.
Whatever you do, stop using REORGANIZE unless you need to compress LOBS and then do a REBUILD right after that. REORGANIZE doesn't work the way you probably think it does.
If you ever need to shrink your database again (should be a VERY rare event), consider moving the largest index(es) to a new file group before you start.