Most performant way to overlapcast tagged instances?

I want to call workspace:GetPartBoundsInBox on tagged instances called “Prop”. My goal is to get all instances that with “Prop” tagged to it in an area.

Is it better to do:

	local propParam = OverlapParams.new()
	propParam.FilterDescendantsInstances = game:GetService("CollectionService"):GetTagged("Prop")
	propParam.FilterType = Enum.RaycastFilterType.Include
	propParam.MaxParts = math.huge
	
	workspace:GetPartBoundsInBox(...)

or is it better to move the props to a folder and have the filter descendant be 1 object?

	local propParam = OverlapParams.new()
	propParam.FilterDescendantsInstances = {workspace.Map.Props}
	propParam.FilterType = Enum.RaycastFilterType.Include
	propParam.MaxParts = math.huge
	
	workspace:GetPartBoundsInBox(...)

Or is there a better approach to doing this?

A folder is def more efficient.
If you have a few parts in workspace it won’t really matter but for a large number of parts def.

the first option is the cleanest and most readable. Although there’s not much difference in your case… The first option is more correct, the second is more productive

If you have many tagged instances, calling CollectionService:GetTagged() every frame can cause lag. It’s better to fetch the list once and update it only when changes occur. Also, when using OverlapParams.FilterDescendantsInstances, avoid filtering through a massive number of objects — it can lead to performance issues. Instead, consider getting all overlapping parts and manually filtering the ones with the desired tags.

I just confirmed that it’s more efficient to avoid large FilterDescendantInstance tables.

I did a small experiment to test it. I hope this is useful for those looking into this in the future!

Experiment Place

OverlapParamGetTagged.rbxl (73.3 KB)

Experiment

Cost to do a single overlap query:

I created 1024 blue cubes and tagged them with “Blue.” I also grouped them into a folder called BluePoints.
I created 1024 red cubes and tagged them with “Red.” I also grouped them into a folder called RedPoints.

Green ball (Method 1) uses:

local propParam = OverlapParams.new()
propParam.FilterDescendantsInstances = {workspace.BluePoints}
propParam.FilterType = Enum.RaycastFilterType.Include
propParam.MaxParts = math.huge
	
workspace:GetPartBoundsInRadius(...)

Yellow ball (Method 2) uses:

local propParam = OverlapParams.new()
propParam.FilterDescendantsInstances = game:GetService("CollectionService"):GetTagged("Red")
propParam.FilterType = Enum.RaycastFilterType.Include
propParam.MaxParts = math.huge
	
workspace:GetPartBoundsInRadius(...)

Result

I ran the query 1000 times and took the average:

  • Method 1 (Green ball): ~86,527 ns
  • Method 2 (Yellow ball): ~180,597 ns

This is around a 2.1x increase in time when using :GetTagged().

Creating the OverlapParam:

I also wrote some code to check how fast it is to instantiate the OverlapParam.

local startTime = os.clock()

local overlapCast1 = OverlapParams.new()
overlapCast1.FilterDescendantsInstances = {workspace.RedPoints}
overlapCast1.FilterType = Enum.RaycastFilterType.Include
overlapCast1.MaxParts = math.huge

print(sp.Name, "Overlap1 created, took", os.clock() - startTime)

local startTime = os.clock()

local overlapCast2 = OverlapParams.new()
overlapCast2.FilterDescendantsInstances = game.CollectionService:GetTagged("Red")
overlapCast2.FilterType = Enum.RaycastFilterType.Include
overlapCast2.MaxParts = math.huge

print(sp.Name, "Overlap2 created, took", os.clock() - startTime)

Output log

YellowBall Overlap1 created, took 0.000008399947546422482
YellowBall Overlap2 created, took 0.000542099995072931
GreenBall Overlap1 created, took 0.000007299997378140688
GreenBall Overlap2 created, took 0.0003494000411592424

Overlap2 ( :GetTagged() ) took ~349,400-542,100 ns to create, while Overlap1 ( {folder} ) took ~7,300-8,400 ns to create. The average time 445,750 ns for overlap2 and 7,850 ns for Overlap1. This is nearly a 57x increase in time.

Same experiment but with fewer parts

I re-ran the experiment with 192 parts each instead of 1024. Roblox’s runtime initialization is strange, and the numbers will go to different values each time depending on a random order. Overall, the disparity is still present in most initializations.


  • Method 1 (Green ball): ~60830 ns (averaged)
  • Method 2 (Yellow ball): ~75097 ns (averaged)

This is around a 1.2x increase in time when using :GetTagged().

Output log still shows initialization to be slower for :GetTagged().

YellowBall Overlap1 created, took 0.000008500006515532732
YellowBall Overlap2 created, took 0.0000686999992467463
GreenBall Overlap1 created, took 0.000004100031219422817
GreenBall Overlap2 created, took 0.00005289999535307288

Overlap2 ( :GetTagged() ) took ~52,900-68,700 ns to create, while Overlap1 ( {folder} ) took ~4,100-8,500 ns to create. The average time 60,800 ns for Overlap2 and 6,300 ns for Overlap1. This is nearly a 9.7x increase in time.

Experiment Place

OverlapParamGetTagged.rbxl (73.3 KB)

TL;DR / Conclusion

Don’t use :GetTagged() for overlap param filtering:

-- don't do this
local propParam = OverlapParams.new()
propParam.FilterDescendantsInstances = game:GetService("CollectionService"):GetTagged("Prop")

Just organize your objects into a folder/model and pass the model itself into the filter:

-- do this!
local propParam = OverlapParams.new()
propParam.FilterDescendantsInstances = {workspace.Map.Props}

OverlapParams.new() is generally slower when you use :GetTagged() for FilterDescendantsInstances. The difference is 9.7x - 57x increase in time for 192 - 1024 parts.

workspace:GetPart…() is generally slower when you use :GetTagged() for FilterDescendantsInstances. The difference is 1.2x - 2.1x increase in time for 192 - 1024 parts.

Note: This applies to more than just :GetTagged(), this is essentially the behavior for many FilterDescendantsInstances instance compared to a single grouped instance.

Extra note: As others have noted here, the improvement is negligible for very small use cases. Does your game really need a 0.1 ms improvement if you’re only going to call it once? For small use cases, organization is better!

2 Likes