Nasty Lookups in Query plan I've been trying to get rid of expensive lookups in my query plan but cannot seem to get my head around it. 
I understand the idea of creating a covering index to eliminate the need for lookups but I don't know how to approach it with a complicated plan like this. 

Any ideas on how to approach this would really be appreciated.

Query plan can be found here:
https://www.brentozar.com/pastetheplan/?id=HyBbQ0eRr

Thanks
So, a covering index is an index that has all the columns that are needed for your query.
A key lookup happens when the optimizer uses your index to get data, but is lacking one or more columns, so it fetches those from the clustered index.

As for example you have an index seek on Table_22 with the index table_22_promoId_Index.
Afterwards in the plan you see that the key lookup fetched a whole bunch of columns.



If you add all the columns from your output list of the key lookup, into your Table_22_PromoId_Index as included columns, you'll stop having a key lookup, cause now it'll just fetch everything from that index, without needing extra information from your clustered index
Then you can repeat that for the others




  I don't know how to approach it with a complicated plan like this.  


Take it one step at a time, pick one lookup, and try and fix that, then move to the next one.
Also since you're selecting many columns, try and remember that making huge indexes also has downsides on updates/inserts and takes up storage, so be careful not too have too many indexes (All depends on how your specific case though.)  

This is also why people advice you to only select columns you actually need instead of everything, since that makes your indexes more narrow and easier to tune.

A useful read about this topic :
Expensive key lookups


  What confuses me is that the Key Lookup contains something called a "Predicate" and a "Seek Predicate". I haven't seen this before and I'm a little confused by the explanation in the article.


So a seek predicate and a predicate in a key lookup is the same as in your Index seek. What happens is that he'll fetch the data from his clustered index (in the case of a key index) using the Seek predicate. Afterwards if he has to filter that data more, he'll use the predicate for extra filters.

There's a good answer from Joe Obbish explaning it really well:
Difference between seek predicate and predicate