Page URL: Data Stores
Issue Description:
This section talks about the budget of requests for each data store request type:
There’s a lot of problems with this section, and after running some tests on the actual behavior of request limits, I think this section should be re-written to match the actual behavior
What’s written in the section VS empirical tests using GetRequestBudgetForRequestType()
I’ve written some code that has a look which, every second, records the request budget for each DataStoreRequestType enum item.
Code:
local DataStoreService = game:GetService('DataStoreService')
local data = {}
local REQUEST_TYPES = Enum.DataStoreRequestType:GetEnumItems()
function _G.PrintData()
local lines = table.create(#data + 1)
local headingStrs = {'Time', 'Player Count'}
for i = 1, #REQUEST_TYPES do
headingStrs[#headingStrs + 1] = REQUEST_TYPES[i].Name .. ' Budget'
end
lines[1] = table.concat(headingStrs, ',')
for i = 1, #data do
local lineData = data[i]
local lineStrs = {tostring(lineData.time), tostring(lineData.playerCount)}
for i = 1, #lineData.requestBudgets do
lineStrs[#lineStrs + 1] = tostring(lineData.requestBudgets[i])
end
lines[#lines + 1] = table.concat(lineStrs, ',')
end
print(table.concat(lines, '\n'))
end
game.ReplicatedStorage.CCallPrintData.OnServerEvent:Connect(_G.PrintData)
workspace.SetCanCollideToPrint:GetPropertyChangedSignal('CanCollide'):Connect(_G.PrintData)
local timestep = 0
while true do
local requestBudgets = table.create(#REQUEST_TYPES)
for i = 1, #REQUEST_TYPES do
requestBudgets[i] = DataStoreService:GetRequestBudgetForRequestType(REQUEST_TYPES[i])
end
data[#data + 1] = {
time = timestep,
playerCount = #game.Players:GetPlayers(),
requestBudgets = requestBudgets,
}
wait(1)
timestep = timestep + 1
end
This code then, on request, prints out all of this data in CSV format.
I made a spreadsheet using this data, then ran linear regression to get the base slope of each request type over time.
I ran these tests for a test server with 0 players, then 1 player, 2 players, 3 players, and 8 players.
0 players:
1 Player (“Extra per second” subtracts the slope from the 0 Players test):
2 Players (“Extra per second” subtracts the slope from the 2 Players test):
3 Players (“Extra per second” subtracts the slope from the 3 Players test):
8 Players (“Extra per second” subtracts the slope from the 0 Players test):
~~
Edit: It turns out actual roblox servers behave differently from studio tests, so I ran tests again using the same method, but with a server with 1 player, then a with 2 players, 3 players, and 10 players.
These aren’t very consistent with the formulas on the wiki page, and the wiki page also excludes SetIncrementAsync, which is super useful information to know
A table with improved formulas
Methods | Initial Requests Reserved | Additional Requests Reserved Per Minute | Max. Requests Reserved |
---|---|---|---|
-------- | -------- | -------- | -------- |
GlobalDataStore:GetAsync, OrderedDataStore:GetAsync, GlobalDataStore:UpdateAsync*, OrderedDataStore:UpdateAsync* | 180** | 60 + 40 * (Number of Players in Server) | 3 * (60 + 40 * (Number of Players in Server) |
-------- | -------- | -------- | -------- |
GlobalDataStore:SetAsync, GlobalDataStore:IncrementAsync, GlobalDataStore:RemoveAsync, GlobalDataStore:UpdateAsync* | 180** | 60 + 40 * (Number of Players in Server) | 3 * (60 + 40 * (Number of Players in Server) |
-------- | -------- | -------- | -------- |
OrderedDataStore:GetSortedAsync, DataStorePages:AdvanceToNextPageAsync | 15** | 5 + 2 * (Number of Players in Server) | 3 * (5 + 2 * (Number of Players in Server) |
-------- | -------- | -------- | -------- |
OrderedDataStore:SetAsync, OrderedDataStore:IncrementAsync, OrderedDataStore:RemoveAsync, OrderedDataStore:UpdateAsync* | 90** | 30 + 5 * (Number of Players in Server) | 3 * (30 + 5 * (Number of Players in Server) |
* The request budget for UpdateAsync is the minimum of the request budget for GlobalDataStore:SetAsync and GlobalDataStore:GetAsync for GlobalDataStores; for OrderedDataStores, it is the minimum of the request budget for OrderedDataStore:GetAsync and OrderedDataStore:SetAsync
** These initial values are from from exactly 1 second after the server scripts ran, and might not be perfectly precise.
Also worth noting: I haven’t tested this on a larger place with more players, so I’m assuming the behavior remains consistent when more players join the game. This assumption could possibly be wrong though?
What I would like to see on this devhub page
- Accurate values for each request type
- A better explanation of how these requests are reserved, specifically mentioning that they accumulated every few seconds with a period that depends on the minute budget quota, and the number of players in the server at that given point in time.
- The initial number of requests rewarded for each budget type
- The maximum number of requests that can accumulate for each budget type
- Some tips on how to effectively budget data store requests. Relying on the raw “requests per minute” rate is not great advice; it’s better to think in terms of available requests at a given time, and then be mindful of how fast new requests come in that can be budgeted.