In the API, crm_update_contact() allows me to pass the $contact record, but also specifically the $params that I'd like changed. This is, so I'm told, to reduce the number of queries - the API will only write SQL for the updated values, and not waste time updating things that haven't change. This doesn't, however, appear to be happening in the UI forms for contact creation/updating, which can cause creation/updating to take a decent amount of time for those with large datasets (2 million contacts in my particular case).
- After the form has been submitted, _get the contact ID and do a compare. In my entirely unscientific tests, getting contacts is always faster than setting all the values again. Once the contact has been gotten, we can compare the original values to the received value, and issue updates like the API (only for changed data, not everything).
- In the form UI itself, include copies of all the user-modifiable data in non-modificabe "original_$elementname" hidden form elements. When the form is submitted, both the possibly-changed data from the user, and the original database values, are received by the code, and a comparison can happen there on what has really changed.