-2

Which would be faster and more efficient memory-wise?

  1. A CFM file containing individual CFQUERY calls
  2. A CFM file containing individual CFINVOKE calls to CFC's containing individual methods for each of those same queries

I realize there are different ways of invoking methods of a component, such as using createobject. For now, let's limit the discussion to just the above two options.

I don't have any sample code. Just want to know what would be considered best practice in the above situation.

Also, I am using newer versions of Adobe ColdFusion (2016, 2018, 2021), so Lucee is not an option.

James A Mohler
  • 11,060
  • 15
  • 46
  • 72
  • 2
    In short, option #2 is the recommended practice. You want to store back-end processing in CFC files, which act like objects, all as part of the bigger CFM file, which acts as a class. Running queries in a CFM page is generally bad practice, unless you wrap them in a ``. – Max Voisard May 02 '22 at 23:15
  • That is what I thought, but besides best practice, I was wondering if there is a performance difference? – RickInWestPalmBeach May 02 '22 at 23:22
  • 1
    That is a harder question to answer, but looking at your situation, when you say the queries are the same, then this should still probably be implemented as a CFC so you can have one stateful query object, and the data and the methods can be encapsulated in their own memory space. If I had a closer look at your code, that would help, but this seems to be the best solution from what you've given. And if there's any speculation on which performs faster, there's always CF's `getTickCount()` method. – Max Voisard May 02 '22 at 23:36
  • I did an experiment, and found pages loading 40% faster with CFINVOKE. – RickInWestPalmBeach May 03 '22 at 01:14
  • Wow, that's a significant performance boost. Good find. – Max Voisard May 03 '22 at 02:28
  • 4
    You didn't describe the experiment. Something I noticed over the years is that if you run the same query twice in rapid succession, it will be faster the second time. – Dan Bracuk May 03 '22 at 03:55
  • There is a page that was written in CFML before CFC's existed that pre-loads javascript arrays by wrapping the javascript with ColdFusion. This page is SCREAMING to be converted to AJAX, but that is another story. This page executes over 1000 queries every time the page loads. I executed the page 10 times with CFQUERY and then after using CFINVOKE and a component. The average savings was 40%. – RickInWestPalmBeach May 03 '22 at 11:30
  • @MaxVoisard it's interesting that you say running queries in a CFM page is considered bad practice, considering the fact that every instructor led CF course I've taken from Adobe, was always taught it that way. It's also true that all those Adobe CF courses I've taken are from the late 90s and early 2000s and I'm guessing course curriculums have changed since then. – user12031119 May 03 '22 at 13:43
  • @user12031119 It seems curriculums back around CF's inception pointed more towards usage of the CFM file, but of course we're in CF 2021 now. Coming from the OOP world, it seems that the CFCs are to be used for entity classes and controller classes and the CFM is basically the presentation class. Therefore, calls to component methods to query data seems best practice, but there certainly isn't a constraint on which to use. – Max Voisard May 03 '22 at 14:36
  • @MaxVoisard Add an answer to the question so i can mark your response as the answer. – RickInWestPalmBeach May 03 '22 at 15:19
  • 1
    Instead of worrying about cfm vs cfc performance, a better question is why is a single page running **"...over 1000 queries every time the page loads"**? That's the real performance issue that should be addressed IMO. – SOS May 04 '22 at 01:43
  • Running in CFM: Maybe faster, but not a great practice. Running in CFC: Perhaps the same as running in CFM, considered good practice. – akashb May 04 '22 at 05:19
  • @SOS Yes, I already addressed the fact that it really needs to be converted to AJAX, but it served its purposes for the performance test. – RickInWestPalmBeach May 04 '22 at 17:14
  • @RickInWestPalm - 1000 queries per page load strongly suggests a *design* problem, not an ajax problem. Even with ajax, it is not scalable. – SOS May 04 '22 at 20:29
  • @SOS The design problem is that it it isn't using AJAX. The page in question has drop-downs where subsequent drop-downs are populated based on the prior selected values. Currently, EVERY possible combination is being pre-loaded into javascript arrays on the page, hence the 1000+ queries. Upon further inspection into the page, it turns out that it is executing 1 database query and 1000+ query of queries using the original database query values. Regardless, it is still bad design and should be written to use AJAX. – RickInWestPalmBeach May 06 '22 at 12:27

2 Answers2

4

I think the question is naive. Option (1) will be faster because it involves less code and fewer moving parts. I would really like to see the test mentioned in the comments that claims the "cfinvoke" version is faster. I suspect the test is flawed, or not testing like-for-like.

However this sort of performance consideration is the sort of thing one looks at after one has written good code (so... not the first option. Definitely not that), and one detects a performance issue. Real world performance gains will seldom be made in this sort of code differentiation.

Write good, clean, well-designed, easy-to-maintain code. Do that first. Only revert back to shonky code to try to eke out that last millisecond if you really need to. But still: <cfquery> tags directly in .cfm files is "never" going to be part of that solution.

Adam Cameron
  • 29,677
  • 4
  • 37
  • 78
  • Since when does the number of moving parts dictate performance? Regardless of the number of moving parts, using CFINVOKE is continually and substantially faster, most likely because CFC's are compiled in the back end. The test is not flawed. It is a simple replacement of CFQUERY with CFINVOKE calling the identical queries in the CFC. Also, when one inherits existing code, it removes the possibility of writing good code from the outset. – RickInWestPalmBeach May 04 '22 at 17:19
  • 1
    @RickInWestPalmBeach Moving parts such as calling the procedure, pushing to and popping from the call stack and additional memory allocation. Obviously doing just A is faster than doing B to do A. Your "test" should not show a difference at all, because you can barely measure time deltas in the range of mere microseconds in ColdFusion, especially not on a HotSpot JVM. You are not in control of the generated Bytecode. `cfm` templates are compiled just like `cfc` components, no difference here. Your methodology is off, which is unsurprising considering your question is a beginner's one. – Alex May 06 '22 at 12:55
  • @Alex pretty much nailed it there. Rick mate: if you don't want an answer, don't ask a question yeah? As I observed in my answer, we can't really make sensible commentary on why your tests show what they do because you haven't shown us the test or the code you're testing. So we kinda have to guess. – Adam Cameron May 07 '22 at 09:19
1

In short, option #2 is the recommended practice. You want to store back-end processing in CFC files, which act like objects of entity classes and controller classes, all as part of the CFM file, which acts as a presentation class. These protocols all stem from the object-oriented programming paradigm.

Now, with using component methods generally being the better choice for holding queries, (1) it doesn't mean you are constrained to this option and (2) that doesn't answer the question of which performs better. Yet, the query should still probably be called from a component method. Since you have the same query, you can simply make one stateful query object and the data and the methods can be encapsulated in the same memory space, leading to an overall performance boost.

Max Voisard
  • 1,685
  • 1
  • 8
  • 18