I have a site with pages, each page may belong to several categories. Users are assigned to categories, and if a page has is assigned a category that a user belongs they can see the page.
originally each page belonged to one category, I could join with this table and check the permission like so
where Sec.[level] > 0
Now that pages can have multiple categories I've attempted to change the where statement of the SP that filters out results, and although it works it is greatly inefficient. I am getting the max permission of all the categories, and if at least one is greater than zero then access is granted
WHERE
(
(TLA.RecipientTypeID = 2 and (SELECT MAX(CAST(dbo.PersonHasPermission_forSection(CS.SectionID, @pViewersID, 1) AS tinyint))
FROM CONTENT_SECTION CS
WHERE CS.ContentID = tla.RecipientID) > 0
)
OR
(TLA.RecipientTypeID <> 2 AND Sec.[level] > 0)
)
the or is because only pages have multiple cats, other types of content still have only one.
I don't know if there is enough info here but any optimisation tips would be greatly appreciated.

dbo.PersonHasPermission_forSection(..)) is the problem. You need to either in-line it or change it into an inline Table Valued function. Post it's contents and we can show you how to do that.