Separate table or usermeta

The obvious advantage of user meta is that you can use the WordPress API to record and retrieve these extra columns, without writing extra PHP classes or SQL queries. The wp_usermeta table is pretty well indexed, in fact, it uses one row per field (rather than one column if you use a custom table), and you don’t have to worry about performance. Using the user meta API typically means faster development if you only want to record extra fields.

But ultimately, it depends on how you’ll be retrieving the data. For a custom table, you can do:

SELECT `appname`.* FROM `appname` WHERE `appname`.`income` >= 100000;

However, it’ll be a bit more difficult with user meta, and you have to do a join:

SELECT `wp_users`.* FROM `wp_usermeta`
LEFT JOIN `wp_users` ON (`wp_usermeta`.`user_id` = `wp_users`.`ID`)
WHERE `wp_usermeta`.`meta_key` = 'appname_user_income'
AND `wp_usermeta`.`meta_value` >= 100000;

As you can see, this will give you a row in wp_users, to fetch other meta value, you have to call the API based on the user_id you retrieved. (Note, you don’t need a left join just to get the user id).

Therefore, if you only want to run simple queries on your meta fields, you can use user meta to save you a lot of development time. But if writing those queries will be complicated, it’s possible that using your own table would be a better choice.