The second option is definitely the best one, as it involves no downtime and no risk of damaging your database (hey, that can happen during a defrag); just make sure to turn on circular logging on both databases between which you are moving mailboxes, or the transaction logs will quickly fill up your disk space (and then turn it back off as soon as you finish moving those mailboxes).
On the subject of transaction logs: are you taking regular backups with an Exchange-aware backup software? This is not only for the safety of your data, but also because otherwise transaction logs will never be truncated, because Exchange only truncates them after a successful backup (and you shoud definitely not delete them manually).
Last but not least: while shrinking your database size might look like a good temporary solution, please keep in mind that your database will grow back again as soon as more messages get stored in it; make sure to account for database growth, or at the very least to use mailbox quota to avoid people overfilling it; an Exchange server running out of disk space is a situation in which you just don't want to be.
About hidden system mailboxes: the standard
Get-Mailbox cmdlet will not even show them, but you can use the
-arbitration parameter to list them:
Get-Mailbox -Arbitration -database YourDBName
You can then pipe the command output into whatever command you use to move the mailboxes to another database.