DBAtlas · Database operations atlas

Post-migration verification (row count/checksum)

Oracle

-- Compare row counts on source and target
SELECT 'customer' table_name, COUNT(*) row_count FROM customer;

-- To find content differences at object level, DBMS_COMPARISON (via db link)
BEGIN DBMS_COMPARISON.CREATE_COMPARISON(
  comparison_name => 'COMPARE_CUSTOMER',
  schema_name => 'SHOP', object_name => 'CUSTOMER',
  dblink_name => 'TARGET_DB'); END;
/
-- SELECT DBMS_COMPARISON.COMPARE('COMPARE_CUSTOMER', scan_info) FROM dual;

The quickest check is to compare COUNT(*) per table on both sides. To find real row-level content differences, use the DBMS_COMPARISON package: it compares the source and target tables row by row over a database link and can report/converge the differences. For checksums, a column digest can be taken with ORA_HASH or STANDARD_HASH.

PostgreSQL

-- Row count
SELECT count(*) FROM customer;

-- Ordered digest (checksum) of the whole table content — compare on both sides
SELECT md5(string_agg(t.row_md5, '' ORDER BY t.row_md5)) AS digest
FROM (SELECT md5(customer::text) AS row_md5 FROM customer) t;

The first step is to compare count(*) on each table. For content verification, md5 the text representation of each row, concatenate them in sorted order and hash again; this gives an order-independent checksum across the two sides. For large data, take the digest over only the mutable/key columns; ordering by PK matters for repeatability.

MySQL

-- Built-in table checksum (run on both servers and compare)
CHECKSUM TABLE customer;

-- Row count
SELECT COUNT(*) FROM customer;

-- Preferred tool for live/large environments (compares row chunks online):
-- pt-table-checksum h=source,D=shop  (Percona Toolkit)

In MySQL, CHECKSUM TABLE gives a single checksum of the table content; run it on source and target and compare (engine/version must be the same). Use COUNT(*) for the row count. In live production and for replication consistency, the industry standard is Percona Toolkit's pt-table-checksum; it compares chunk by chunk, online and with low impact.

SQL Server

-- Full row-level comparison (official tool that produces differences)
tablediff -sourceserver S1 -sourcedatabase shop -sourcetable customer \
  -destinationserver S2 -destinationdatabase shop -destinationtable customer

-- Quick aggregate checksum (single query, compare on both sides):
SELECT COUNT_BIG(*) row_count, CHECKSUM_AGG(BINARY_CHECKSUM(*)) digest FROM dbo.customer;

In SQL Server, the official command-line tool that finds row-level differences is tablediff (it reports which rows were added/changed, and with the optional -f writes a fix script). For a quick overall check, CHECKSUM_AGG(BINARY_CHECKSUM(*)) gives a single table digest; compare both sides together with COUNT_BIG(*) (independent of row order).

MongoDB

// Compare document counts (on source and target)
db.customer.countDocuments({});

// For a content checksum, dbHash (md5 digest at collection/DB level):
db.runCommand({ dbHash: 1, collections: ["customer"] });
// -> compare the md5 field across both environments.

The first check is to compare document counts on both sides with countDocuments() (estimatedDocumentCount is fast but relies on metadata; use countDocuments for an exact count). For content verification, the dbHash command produces an md5 digest at collection/database level; compare the hashes of the two environments. Check indexes separately with getIndexes().

Redis

# Compare key counts (on source and target)
redis-cli DBSIZE

# For a memory/data summary and key distribution:
redis-cli INFO keyspace     # db0:keys=... information
# For full content verification: DUMP each key and compare with the target
# (e.g. redis-cli --scan | xargs -I{} redis-cli DUMP {})

In Redis, basic verification is comparing the total key count with DBSIZE; the per-database distribution is shown by INFO keyspace. Redis has no built-in table checksum; if exact content verification is needed, take the DUMP serialization per key and compare both sides (keep TTL differences in mind). The riot compare tool can also be used.

Elasticsearch

# Compare document counts (on source and target clusters)
GET customer/_count

# Details: for health/segment/storage comparison
GET _cat/indices/customer?v&h=index,docs.count,store.size
# Content by sampling: compare GET customer/_doc/<id> for the same _ids

In Elasticsearch, basic verification is comparing document counts on both clusters with GET <index>/_count (_cat/indices docs.count also gives a quick summary). Base the comparison on _count: _cat/indices docs.count counts at the Lucene level (including nested sub-documents, e.g. one document with two nested items counts as 3), so it can differ from _count. For content verification, compare by sampling documents over the same set of _ids or via a hash field.

Open in DBAtlas →