Index: modules/field/modules/field_sql_storage/field_sql_storage.module
===================================================================
--- modules/field/modules/field_sql_storage/field_sql_storage.module	(revision 2349)
+++ modules/field/modules/field_sql_storage/field_sql_storage.module	(working copy)
@@ -369,6 +369,75 @@
 }
 
 /**
+ * Callback for array_filter().
+ */
+function _field_sql_storage_write_compare_filter_callback($value) {
+  return null !== $value && '' !== $value;
+}
+
+/**
+ * Cleanup field values for later values comparison.
+ *
+ * @param array $array
+ *   Field values to cleanup.
+ *
+ * @return array
+ *   Filtered array.
+ */
+function _field_sql_storage_write_compare_filter($field, $array) {
+  foreach ($array as $language => $items) {
+    if (empty($items)) {
+      unset($array[$language]);
+    }
+    else {
+      foreach ($items as $delta => $item) {
+        if (!is_array($item)) {
+          continue;
+        }
+        // Let's start by pruning empty values and non storable values.
+        $array[$language][$delta] = array_filter(array_intersect_key($item, $field['columns']), '_field_sql_storage_write_compare_filter_callback');
+        // Ordering is important because for widget elements and loaded
+        // columns from database order might differ and give false
+        // positives on field value change, especially with complex
+        // fields such as image fields.
+        ksort($array[$language][$delta]);
+      }
+    }
+  }
+  return $array;
+}
+
+/**
+ * Compare a single field value for both entities and tell us if it changed.
+ *
+ * @param array $field
+ *   Loaded field structure.
+ * @param stdClass $entity1
+ *   First entity to compare.
+ * @param stdClass $entity2
+ *   Second entity to compare.
+ *
+ * @return boolean
+ *   True if field value changed, false otherwise.
+ */
+function _field_sql_storage_write_compare($field, $entity1, $entity2) {
+  $field_name = $field['field_name'];
+  if (empty($entity1->$field_name) && empty($entity2->$field_name)) {
+    // Both are empty we can safely assume that it did not change.
+    return false;
+  }
+  if (!isset($entity1->$field_name) || !isset($entity2->$field_name)) {
+    // One of them is missing but not the other the value changed.
+    return true;
+  }
+  // We need to proceed to deep array comparison, problem is that we
+  // can't do it naively: in most cases the field values come from
+  // the edit form, and some Form API widget values that are not
+  // field columns may stale in the structure items. We need to clean
+  // up both original and new field values before comparison.
+  $items1 = _field_sql_storage_write_compare_filter($field, (array)$entity1->$field_name);
+  $items2 = _field_sql_storage_write_compare_filter($field, (array)$entity2->$field_name);
+  return $items1 !== $items2;
+}
+
+/**
  * Implements hook_field_storage_write().
  */
 function field_sql_storage_field_storage_write($entity_type, $entity, $op, $fields) {
@@ -377,8 +446,27 @@
     $vid = $id;
   }
 
+  // Check if the given entity is a new revision or not. In case of a new
+  // revision creation, we cannot skip any field else the new revision would
+  // be empty.
+  if (!empty($vid) && !empty($entity->original)) {
+    list(, $original_vid) = entity_extract_ids($entity_type, $entity->original);
+    if (null === $original_vid) {
+      $original_vid = $id;
+    }
+    $is_new_revision = $original_vid != $vid;
+  }
+  else {
+    $is_new_revision = false;
+  }
+
   foreach ($fields as $field_id) {
     $field = field_info_field_by_id($field_id);
+
+    if (!$is_new_revision && !empty($entity->original) && !_field_sql_storage_write_compare($field, $entity, $entity->original)) {
+      continue;
+    }
+
     $field_name = $field['field_name'];
     $table_name = _field_sql_storage_tablename($field);
     $revision_name = _field_sql_storage_revision_tablename($field);
