
A customer asked us why connecting to their 40,000-tag OPC UA server took eleven minutes, on a gigabit link, from a machine in the same rack. Bandwidth was not the problem. It never is.
What CreateMonitoredItems actually costs
When a client subscribes to a node, the server must resolve the NodeId, check access rights, allocate a monitored item, register it against the subscription, and start sampling. That is a handful of milliseconds — trivially cheap.
Done 40,000 times, sequentially, over a request/response protocol with a network round trip in between, it is eleven minutes.
The fix is not faster hardware. It is CreateMonitoredItems accepting an array.
40,000 items × 1 per request = 40,000 round trips ≈ 11 min
40,000 items × 500 per request = 80 round trips ≈ 9 s
The service was always designed to be batched. Plenty of client libraries expose a convenient subscribe(nodeId) helper and quietly issue one request per call.
Sampling interval versus publishing interval
These get conflated constantly, and getting them wrong wastes far more server capacity than any amount of tag count.
- Sampling interval — how often the server reads the underlying value. Costs server CPU.
- Publishing interval — how often the server sends accumulated changes to you. Costs network and client CPU.
Setting a 100 ms sampling interval on a temperature that moves once a minute burns server CPU 600 times over for no information gained. Setting a 1000 ms publishing interval with a 100 ms sampling interval is usually correct for fast values: the server catches every transition, and you receive them in efficient batches of ten.
Deadbands are free capacity
An absolute deadband tells the server not to report a change smaller than a threshold. On analogue values sitting in electrical noise, this routinely removes 80–95% of notifications.
The subtlety: a deadband applies to the reported value, not the sampled one. The server still samples at your sampling interval — you are saving network and client processing, not server CPU. To save server CPU you must lengthen the sampling interval, and that is a conversation about how fast the process actually moves.
A tuning checklist
- Batch
CreateMonitoredItems— 500 to 1,000 items per request. - Set the sampling interval from process dynamics, not from habit.
- Set the publishing interval to 5–10× the sampling interval for fast values.
- Apply absolute deadbands to every analogue that lives in noise.
- Set
QueueSizeto 1 withDiscardOldestunless you genuinely need every intermediate transition. - Use one subscription per sampling rate, not one per screen.
That customer's connection now takes nine seconds and the server's CPU sits 40% lower than it did before, serving the same data.
- #Performance
- #OPC UA


