Looking at your results, actually you should know that dedup can take multiple fields in which case you wind up with all unique sets of fields:
base search | dedup server_name, userid
To try this out you could mock up your example data, with a base search like:
| noop | stats count | eval raw = split("server1,user1;server1,user2;server1,user2;server1,user3;server1,user4;server2,user1;server2,user1;server2,user1;server2,user2;server2,user3;server2,user4;server2,user4",";") | mvexpand raw | eval server=mvindex(split(raw,","),0) | eval user=mvindex(split(raw,","),1) | fields server,user
Then compare the result to:
| noop | stats count | eval raw = split("server1,user1;server1,user2;server1,user2;server1,user3;server1,user4;server2,user1;server2,user1;server2,user1;server2,user2;server2,user3;server2,user4;server2,user4",";") | mvexpand raw | eval server=mvindex(split(raw,","),0) | eval user=mvindex(split(raw,","),1) | fields server,user | dedup server_name, userid
... View more