Why storing constantly changing data on parts using attributes is a bad idea

You should change the title from "SetAttribute is highly unoptimized for usage in loops" to something that better conveys the overall gist of this thread.

To reiterate from my first post, the gist of this thread is:

So a title that’d be more suitable would be:
"PSA: Why you shouldn't store frequently mutated state through instances"

1 Like

Most likely due to the replication overhead. You’ll also see a reduction in network send/recv.

Rule of thumb is to not use them if not everyone has to see the data. Usually only one player needs to see the data, so a custom replication system is better.

I do think the tutorial is nice but this is a known fact, as said before indexing a raw-memory dictionary is going to be exponentially faster than what Roblox does which is fetch the memory address of the property by indexing the instance, then read it, then return it.

This is why we need a guide explaining common code standards and efficient methods of storing data.

Sorry to bump this thread, but I want to provide more context to the test in the original post as its a bit biased towards a single use-case and a tad misleading. I don’t disagree with the opinion of the original poster, but I have different reasons for using alternatives to SetAttribute.

The test in the original post assumes that the data you are setting / using only exists on the server, in which case yes, storing data in a table would be the fastest and most efficient method. However, SetAttribute comes with a caveat, and that is the fact that setting an attribute on the instance replicates to the clients - just like any other property on an instance would. So let’s say you want to use this stored information on the client for display purposes. The correct code snippet that compares both SetAttribute and the table storage with RemoteEvents for network replication would actually look more like the following…

local AmazingDictionary = {
	Health = 0,
	Speed = 0,
}
local AttributeHolder = Instance.new("Part",workspace)

local AttributeTime = os.clock()
for i = 1,10000 do
	AttributeHolder:SetAttribute("Health",i)
	AttributeHolder:SetAttribute("Speed",i)
end
print(os.clock() - AttributeTime)

local DictionaryTime = os.clock()

for i = 1,10000 do
	AmazingDictionary.Health = i
	game.ReplicatedStorage.RemoteEvent:FireAllClients({
		health = AmazingDictionary.Health
	})
	AmazingDictionary.Speed = i
	game.ReplicatedStorage.RemoteEvent:FireAllClients({
		speed = AmazingDictionary.Speed
	})
end

print(os.clock() - DictionaryTime)

Doing this we see that SetAttribute is around 30ms and table with RemoteEvents is around 55ms.

for i = 1,10000 do
	AmazingDictionary.Health = i
	AmazingDictionary.Speed = i
		
	game.ReplicatedStorage.RemoteEvent:FireAllClients({
		speed = AmazingDictionary.Speed,
		health = AmazingDictionary.Health
	})
end

Further optimizing the RemoteEvents method to combine all property changes into a single RemoteEvent call reduces the time to about 30ms, the same as two SetAttribute calls. Which means that RemoteEvents become more efficient as more data is combined into a single network call (given the amount of data being set in both methods is the same size).

So in conclusion, don’t use SetAttribute if your plan is to only use the values on the server and you’re doing this in large quantities. It is creating needless network events which will start to cause network bottleneck, and eventually FPS drops. Small quantities of SetAttribute is negligible and will cause no noticeable impact to your game’s network performance. If you plan to utilize this data on the client in some way, it would be acceptable to use SetAttribute for a small quantities of values (e.g. health, speed, damage, state), but anything over 3-4 will start to show a noticeable difference when compared to RemoteEvents. Personally, I prefer RemoteEvents as they are more customizable with who the data is replicated to, but SetAttribute can be a convenient and easy alternative in the right circumstances.

4 Likes