WooCommerce variations are posts with the variable product as parent

A variable product looks like one thing in the admin and is not one thing in the database. The product is a single product post; each variation is a separate post of type product_variation whose post_parent is that product, with its price, stock and chosen attribute values held as postmeta on the variation rather than on the parent.

SELECT v.ID, v.post_parent, m.meta_key, m.meta_value
  FROM wp_posts AS v
  JOIN wp_postmeta AS m ON m.post_id = v.ID
 WHERE v.post_type   = 'product_variation'
   AND v.post_parent = 4412
   AND m.meta_key IN ( '_price', '_stock', 'attribute_pa_size' );

-- 8831 | 4412 | _price            | 49.00
-- 8831 | 4412 | _stock            | 3
-- 8831 | 4412 | attribute_pa_size | 52
-- 8832 | 4412 | _price            | 52.00
-- 8832 | 4412 | _stock            | 0
-- 8832 | 4412 | attribute_pa_size | 54

-- variations whose parent has been deleted, which an import will leave behind
SELECT v.ID FROM wp_posts AS v
  LEFT JOIN wp_posts AS p ON p.ID = v.post_parent
 WHERE v.post_type = 'product_variation' AND p.ID IS NULL;

Three details follow from the layout and each one costs somebody a day eventually. The value stored in attribute_pa_size is the term slug, not the term id, so renaming a slug on the attribute taxonomy silently detaches every variation that referenced it and the product starts reporting itself out of stock. An empty value in that meta key means “any”, which is why a half-configured variation matches every size and shadows the specific ones underneath it. And variations have no title of their own, so an admin search for a SKU will not find them and a query for post_type => 'any' will. Reading the meta directly is fine for a report and wrong for anything that renders a price — $product->get_available_variations() applies the filters other extensions hang their pricing on. If you do write to the tables in bulk, clear the cached price ranges afterwards with $woocommerce->clear_product_transients( 4412 ), or the catalogue keeps showing the old figures until they expire on their own.