On Oct 31, 2009, at 11:46 am, Andrew Threlfall wrote:

> The system needs to be able to do processing to see the ingredients
> based on a subset of the recipes eg vegetarian ones.  So I essentially
> want to see the ingredients in all the vegetarian recipes in all the
> books in my account. In this instance the ingredients are all unique,
> and not common for other recipes. Also if someone wants to view or
> edit ingredient with id 20,000 how do I very quickly know if that one
> of theirs?

You don't say if the books are specific to users or not, but  
presumably the recipes are specific to books.  So I'm guessing your  
relations look like this (I hope you're have a fixed-width font):

                RecipeCategories
                       1
                       |
                       ∞
User 1-∞ Books 1-∞ Recipes 1-∞ Ingredients

Or the only difference is a many-many connection between Users and  
Books.  Because you mention putting user ids further down the tree,  
I'm assuming that's not the case.


> The model names have been changed, but the analogy is more or the less
> the same.

I did wonder if you really were working on Delia 3.0 =)


> Technically it's possible with scoping, but more a case of wondering
> if there is any good practice that will mean this can be done
> efficiently. I don't want to be joining potentially hundreds of
> thousands of rows, or adding permission methods to models, or adding
> user or account ids to models further down the tree too early, but I
> can see it becoming a problem very soon.

I can see a few options:

* Suck it and see

Take a chance that performance will not be an issue.  Without  
benchmarking, I'd (personally) be inclined to go down this route.  But  
the risk rises as the consequences of long page loads become more  
severe, or if you thought you'd lose business faster than you could  
fix the problem.  If users would put up with poor performance for a  
few weeks, and you know the lead time on implementing a story is 2-3  
days, it may be a risk worth taking.


* Make the work asynchronous

This may or may not be an option based on the way you're accessing the  
data.  But you could load the screened data asynchronously, and use  
JavaScript to make the interface more responsive.  You'd still have  
the performance issue, but it may be perceived as less severe, which  
would reduce the pressure to fix it later.


* Implement explicit permissions at each level

This would involve adding user_book_permission, user_recipe_permission  
etc tables.  You'd have to enforce consistency with business rules  
somewhere (presumably, you'd have to have recipe permissions to get  
ingredient permissions).  There would be a lot more work there on  
setting permissions, but a lot less work using them.

I don't have a name for this technique, but I think of it as "naming  
the fact".  You could consider the fact that a user can see an  
ingredient as implicit, because he owns it, or you could "name the  
fact" of user-has-permission-to-see-ingredient and record it  
explicitly.  Often this can be done without introducing redundancy if  
you name the fact right.

Ask me to elaborate if you want, I'm not sure that explanation is clear.


* Benchmark and optimise

Do you have an idea of the proportion of data real users will have at  
each point?  If the Ingredients is where most of the data goes it  
might not even be an issue.

The join to get at the Ingredients for a category of recipes would be  
something like (I'm using natural join[1] to save writing all the  
fluff, although this doesn't actually work with ActiveRecord naming  
conventions):

   ingredients
     NATURAL JOIN recipes
     NATURAL JOIN recipe_categories
     NATURAL JOIN books
     NATURAL JOIN users
   WHERE recipe_category_id IN (X)
   AND user_id = Y

Be aware I obviously didn't test that, so it might actually be wrong.

Now, then regardless of how many ingredients you have, it depends if  
your query optimiser will realise that `WHERE recipe_category_id IN (X) 
` will restrict the join soonest. ie, will it find all the requested  
recipes and either return them, or throw them away because the user_id  
was wrong?  Postgres does this quite happily, I can't say for MySQL  
(I've met people who've had to force the order of the query clauses to  
make the optimiser work correctly).

I don't know how to go about generating that query in ActiveRecord,  
but an interesting discussion on the DataMapper list came up recently 
[2].

If you don't have the option to restrict the query further down, ie a  
user could request an Ingredient with no context, you'd have to rely  
on join performance.  Is this a normal use case?  If not, you could  
suck it and see.


Hmm, that turned into a bit of an essay once I got started.  Not sure  
how helpful it is, but it was useful to me as I now realise why I  
favour "suck it and see".  Anyway, that's the thought process I use,  
even if the concrete examples are not relevant.


Ashley


[1] http://en.wikipedia.org/wiki/Join_(SQL)#Natural_join
[2] 
http://groups.google.com/group/datamapper/browse_thread/thread/4f693f297c17aa6d


-- 
http://www.patchspace.co.uk/
http://www.linkedin.com/in/ashleymoran
http://aviewfromafar.net/


--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups 
"NWRUG" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/nwrug-members?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to