# Execution speed comparison of system.tag.query / browse --\> browse wins

**URL:** <https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175>\
**Category:** Ignition\
**Tags:** ignition81, scripting\
**Created:** [December 15, 2023, 1:23am UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175 "2023-12-15T01:23:12Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![nminchin](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/nminchin/32/6911_2.png) [@nminchin](https://forum.inductiveautomation.com/u/nminchin)\
**Post date:** [December 15, 2023, 1:23am UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/1 "2023-12-15T01:23:12Z")

</div>

I always wanted to compare these two functions to see which won, and spoiler alert, it's `system.tag.browse` by more than an order of magnitude! At least for my very small site and test case...

sampling execution count = 50  
`system.tag.browse` = 15ms  
`system.tag.query` = 206ms

> **Code**
>
> ```python
> provider = 'default'
> query = {
> "options": {
> "includeUdtMembers": True,
> "includeUdtDefinitions": False
> },
> "condition": {
> "tagType": "UdtInstance",
> "attributes": {
> "values": [],
> "requireAll": True
> },
> "properties": {
> "op": "Or",
> "conditions": [
> {
> "op": "And",
> "conditions": [
> {
> "prop": "typeId",
> "comp": "Equal",
> "value": "<Specific UDT Type>"
> }
> ]
> }
> ]
> }
> },
> "returnProperties": []
> }
> 
> tests = 50
> from java.lang.System import nanoTime as nt
> 
> def average_execution_time(func, num_executions):
> total_execution_time = 0
> 
> for _ in range(num_executions):
> start_time = nt()
> func() # Call the function passed as an argument
> end_time = nt()
> 
> execution_time = end_time - start_time
> total_execution_time += execution_time
> 
> # Calculate the average execution time
> average_time = total_execution_time / num_executions
> 
> return average_time
> 
> def q():
> system.tag.query(provider, query)
> def browse():
> system.tag.browse('[default]<Base Area folder to exclude _types_ folder>', filter={'recursive': True, 'tagType': 'UdtInstance', 'typeId': "<Specific UDT Type>"})
> 
> average_execution_time(q, 50)/1000000
> average_execution_time(browse, 50)/1000000
> 
> ```

> **Default Tag Provider Summary**
>
> Code: [Ignition Tag Count in a project - #2 by nminchin](https://forum.inductiveautomation.com/t/ignition-tag-count-in-a-project/78201/2)
> 
> # Tag summary for provider "default"
> 
> tagType: {'UdtInstance': 122, 'Folder': 126, 'AtomicTag': 1242}  
> valueSource: {'memory': 234, 'opc': 802, 'reference': 2, 'expr': 195, 'db': 9}  
> dataType: {'Float4': 2, 'Int2': 3, 'DataSet': 55, 'Float8': 206, 'Int4': 415, 'String': 47, 'Int8': 61, 'Document': 1, 'Boolean': 452}  
> tagGroup: {'Default': 1354, 'Alarm Summary': 39, 'ConfigTags\_CMDPLCReset': 73, 'Value Change Triggers': 24}  
> eventScripts: {'eventScripts': 78}  
> historyEnabled: {'False': 1490}

---

<div class="post-metadata">

**Author:** ![cwells](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/cwells/32/35042_2.png) [@cwells](https://forum.inductiveautomation.com/u/cwells)\
**Post date:** [April 5, 2024, 3:34pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/2 "2024-04-05T15:34:00Z")

</div>

Thanks for this writeup! Just including a note for others if they decide to test this as well, don't include a wildcard character (\*) in the path (first argument) of the system.tag.browse() call, since it needs to be the starting folder for the search. This is in contrast to the "Tag Path" field of the Tag Report Tool, which does accept \* as a wildcard.

If curious, my test results was roughly  
.query = 522ms  
.browse = 174ms

Note that my Ignition designer was remotely connected to my test site, which had over 20,000 tags. So, this is probably a "Your mileage may vary" situation, but interesting to explore more. I usually go with .query for the ease of setup, but I will have to give .browse a try again sometime.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [March 29, 2025, 5:50pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/3 "2025-03-29T17:50:45Z")

</div>

I tried pretty much the same thing to test the speed of both functions, and came to the same conclusion: `browse` is much faster than `query`. It's not even close.

But then I tried running them out of a loop, just one call at once, and I noticed something:  
`browse`'s execution time is rather stable. I get around 0.08 secs. Sometimes it goes up to 0.1 secs, but it stays in that ballpark.  
`query`, on the other hand, varies wildly. I can get results in 0.01 secs one time, and 0.3 secs on the next call. That's 30 times longer on the 2nd call !

I was kinda hoping to replace some `browse` calls with `query`, the added flexibility in the filtering would be helpful in some cases, but I guess I'll stick with it for now.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 29, 2025, 5:57pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/4 "2025-03-29T17:57:27Z")

</div>

Use `.query` when you want to recurse into the tree. Use `.browse()` when you don't. Unless you want to grab a bunch of properties. Then using `.query()` is usually faster than `.browse()` followed by `.readBlocking()`.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [March 29, 2025, 5:59pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/5 "2025-03-29T17:59:05Z")

</div>

What do you mean by tree ?  
The tag tree, or the 'property tree' of particular tags ?

My test was using a recursive browse, and it came out ahead.

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 29, 2025, 5:59pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/6 "2025-03-29T17:59:20Z")

</div>

The tag tree.

> [@pascal.fragnoud](#):
>
> My test was using a recursive browse, and it came out ahead.

I find that surprising.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [March 29, 2025, 6:00pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/7 "2025-03-29T18:00:35Z")

</div>

Yes, I guess `query` does remove the need to read the tags afterward to get their values...  
This should probably be included in the test.

---

<div class="post-metadata">

**Author:** ![pascal.fragnoud](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pascal.fragnoud/32/24728_2.png) [@pascal.fragnoud](https://forum.inductiveautomation.com/u/pascal.fragnoud)\
**Post date:** [March 29, 2025, 6:47pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/8 "2025-03-29T18:47:53Z")

</div>

I'm only discovering this function, I completely missed its introduction, so I have to experiment with it a bit, but...

What if I want to read tags in a UDT instance ? Or its parameters ? I can't find a way to do that with `query`.  
Assuming I'll still have to use `readBlocking` to get their values, should I use `query` or `browse` to get the UDT instances paths ?

---

<div class="post-metadata">

**Author:** ![pturmel](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/pturmel/32/3295_2.png) [@pturmel](https://forum.inductiveautomation.com/u/pturmel)\
**Post date:** [March 29, 2025, 7:41pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/9 "2025-03-29T19:41:27Z")

</div>

`system.tag.query()` is the fundamental backing of the Designer's Tag Report Tool. Use that to get a feel for how it works. Yes, it has settings for searching within UDT instances. That tool will also write the sample jython that corresponds to what you've set up.

---

<div class="post-metadata">

**Author:** ![Eugene49](https://avatars.discourse-cdn.com/v4/letter/e/c6cbf5/32.png) [@Eugene49](https://forum.inductiveautomation.com/u/Eugene49)\
**Post date:** [September 16, 2025, 7:53pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/10 "2025-09-16T19:53:22Z")

</div>

Sorry, I didn't see this mentioned.  
Aside from the time it takes to complete. Is tag.query completely alternative to tag.browse.  
What does former can do that the latter cannot? and vice versa?

edit:  
One differenciator I see.  
For tag.browse: must enter strictly parent tag without wildcard, then search for tagName ONLY (accepts wildcard).  
While for tag.query: search complete path (accepts wildcard).

---

<div class="post-metadata">

**Author:** ![danielps1818](https://avatars.discourse-cdn.com/v4/letter/d/ecae2f/32.png) [@danielps1818](https://forum.inductiveautomation.com/u/danielps1818)\
**Post date:** [September 29, 2026, 3:56pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/11 "2026-09-29T15:56:34Z")

</div>

I've been doing test with both functions using @nminchin code.

I've notice that for really big searchs `system.tag.query` performance is really similar as `system.tag.browse`. However, `system.tag.browse` has a higher impact in the CPU.

However, for smaller searches, `system.tag.browse` works INCREDIBLE better. But it has a much bigger impact on CPU (creating a spike on the percentage use).

When using one or another be careful. It could make a really bad impact on an already stressed gateway

---

<div class="post-metadata">

**Author:** ![tgarrison](https://sea1.discourse-cdn.com/inductiveautomation/user_avatar/forum.inductiveautomation.com/tgarrison/32/80965_2.png) [@tgarrison](https://forum.inductiveautomation.com/u/tgarrison)\
**Post date:** [October 1, 2026, 12:07pm UTC](https://forum.inductiveautomation.com/t/execution-speed-comparison-of-system-tag-query-browse-browse-wins/83175/12 "2026-10-01T12:07:10Z")

</div>

This is key. With query, you can have it return a wide variety of info directly in the result. So it can make your overall script MUCH faster.
