There are actually two separate questions being asked here:
- Should I be using LEFT JOINs?
- How can I make my query more efficient?
I'll answer #2 first because I think it's easier. In your query plan, over 70% of your cost comes from the table scan of the "people" table. So, you can optimize your JOINs all day and still not improve your efficiency much. The critical question is, what percentage of your "people" have a "role_id <= 4"? If it's less than 10%, you have some room to optimize based on how you index; if it's more than about 70%-- that is, if the purpose of this query really is to pull a nearly complete list of everyone in the "people" table-- then you pretty much just have to pay what it costs to do that.
Now, about question #1: so long as the following inferences about your data model are true, then your LEFT JOINs are probably the best way to do what you are trying to do. The inferences are:
- A "people" entry has zero-to-one corresponding resume category; that is, people.resume_category_id can be NULL or can have a meaningful value. (If it can have invalid values not found in the parent table, then you have a referential integrity problem and what you need is a foreign key constraint.)
- A "people" entry has zero-to-many emergency contacts.
- A "people" entry has zero-to-many people profiles.
- A "people profile" entry has zero-to-one job titles (as above with resume_category)
- A "people profile" entry has zero-to-one job categories (as above)
- A "people profile" entry has zero-to-one education type (as above)
- A "people profile" entry has zero-to-one source (as above)
- You want to list all people regardless of presence or absence of data in any of these other tables
Hope that helps and all the best.
--- EDIT ---
Hey, something has been bothering me about this answer, and I just now figured out what it is. There is an actual problem with your query structure, but it isn't related to your use of LEFT JOINs. It's that you are joining to two different child tables at once, with both having the same parent table of "people". Depending how your data is actually distributed, this would give you a Cartesian product as your resultset. For example, suppose you have a person "Bob" with two profiles ("Work" and "Home") and two emergency contacts ("Alice" and "Carol"). Then a query structured like yours would give:
Person Profile Contact
------ ------- -------
Bob Work Alice
Bob Home Alice
Bob Work Carol
Bob Home Carol
If the relationships that are structured like zero-to-many can, in fact, have multiple child rows, then the solution depends on how your app is using the data. There are, however, two basic possible approaches:
- Separate each zero-to-many JOIN into its own query, so you would have a total of three queries instead of just one.
- Use some sort of aggregation operator like FIRST or MAX (slightly sketchy since it can give unpredictable results and/or mix-and-match fields from different rows in the resultset).
As a side note, if the child tables can't have multiple child rows, then you should ensure this by putting a unique constraint onto the "people_id" fields of each of those tables.