Trim is not supposed to help with ZFS compression, it occurs at a layer below what the FS sees (but the FS hooks are necessary for the controller to understand the logical use).
The issue TRIM helps with is the following: while reads and writes are performed at the page level (2-16k), a page can not be overwritten (it can only be written to when empty) and an SSD can only erase entire blocks (128~256 pages).
This means when you perform an overwrite of a page, the SSD controller really has an internal mapping between logical pages (what it tells the FS) and physical pages (the actual NAND cells) and it updates the mapping over the overwritten logical page to a new physical page (in which it writes the “updated” data), marking the old physical page as “dirty”.
So as you use the drive the blocks get fragmented, more and more full of a mix of dirty and used pages meaning the controller is unable to erase the block in order to reuse its (dirty) pages. So it garbage-collects pages, which is a form of completely internal defragmentation: it goes through “full” blocks, copies the used pages to brand new blocks, then queues the blocks for erasure.
The issue with this process is… the SSD only knows that a block is unused when it’s overwritten, historical protocols had no more information since the hard drives had the same unit for everything and could overwrite pages, and thus the FS managed that directly. This means if you delete a file the controller has no idea the corresponding pages are unused (dirty) until the FS decides to write something unrelated there, meaning if you do lots of creation and removing (rather than create-and-never-remove or create-and-overwrite) the controller lags behind and has a harder and harder time doing physical defrag and having empty blocks to write to, this leads to additional garbage collection and thus writes, and all the “removed but not overwritten” blocks are still used as far as the controller knows so they’re copied over during GC even though no one can or will ever read them.
TRIM lets the FS tell the controller about file deletions (or truncation or whatever), and thus allows the FS to have a much more correct view of the actually used blocks, thereby allowing faster reclamation of empty blocks (e.g. if you download a 1GB file, use it, then remove it, the controller now knows all the corresponding blocks are dirty and can be immediately queued for erasure) and reducing unnecessary writes (as known-dirty pages don’t have to be copied during GC, only used pages).