The way to get the most accurate split of your audience would be to use a rank() and count() to a staging table and then use math in the following queries to build out your segments.
Staging Query:
SELECT Subscriberkey
, EmailAddress
, Field1
, ...
, rank() over (PARTITION BY SubscriberKey ORDER BY newid()) as rn
, count(Subscriberkey) over (PARTITION BY SubscriberKey) as total
FROM [myMasterDE]
/* Target: staging_table */
Then follow that with 20 queries that target the different DEs you want to split it into:
SELECT SubscriberKey
, EmailAddress
, Field1
, ...
FROM [staging_table]
WHERE rn <= (total * .05)
/* Target: DE_1 */
SELECT SubscriberKey
, EmailAddress
, Field1
, ...
FROM [staging_table]
WHERE rn between (total * .06) AND (total * .10)
/* Target: DE_2 */
SELECT SubscriberKey
, EmailAddress
, Field1
, ...
FROM [staging_table]
WHERE rn > (total * .95)
/* Target: DE_20 */
You can also utilize NTILE() via a staging DE ( NTILE(20)
) to label which group it should be in - with the volume of records, this should get you closer to accurate than the _customobjectkey
and MOD %
function, but it still has a margin of error that some may find unacceptable. The major benefit though is that it is much easier to use and may require less processing than above math example.
NTILE Example
SELECT Subscriberkey
, EmailAddress
, Field1
, ...
, NTILE(20) order by newid() as group
FROM [myMasterDE]
/* Target: staging_table */
Then use 20 queries like below to separate out:
SELECT SubscriberKey
, EmailAddress
, Field1
, ...
FROM [staging_table]
WHERE group = 1
/* Target: DE_1 */
Utilizing the _customobjectkey
is definitely quick as that field is guaranteed to be indexed so its usually faster than other methods, but due to the margin of error (numbers not guaranteed to be consecutive), it may not work for you.