Request Limits on Data Store Errors and Limits page are not accurate

Page URL: Data Store Errors and Limits

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.

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'
	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])
		lines[#lines + 1] = table.concat(lineStrs, ',')
	print(table.concat(lines, '\n'))



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])
	data[#data + 1] = {
		time = timestep,
		playerCount = #game.Players:GetPlayers(),
		requestBudgets = requestBudgets,
	timestep = timestep + 1

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.

Just wanted to append that I wrote an overview of the accurate request limits a while ago here:


Ah, I didn’t realize that studio/plugins allowed for a much higher request count! It looks like, in the live place, you actually start with 580 GetAsync/etc. requests on the server, and then it immediately drops down within the first second or so.

I’ll update the original post to reflect the accurate values. It seems like the 40 per player per minute figure is still accurate for GetAsync/GetIncrementAsync requests? I still haven’t tested this on larger servers though.

It’s possible they tweaked some of the coefficients around in the mean-time. Will run my own tests again some time.

I wonder if they somehow forgot to turn the budget increases off that they made here temporarily: [Update] DataStores Incident: Data Consistency Checker API

40 req/player/minute seems very high considering it was 10 before…

If they did, no snitching please!