From cc0708f1a6e3b8204167af485c81d855cb16d6a7 Mon Sep 17 00:00:00 2001 From: brubbel <5667690+brubbel@users.noreply.github.com> Date: Sun, 20 Jan 2019 12:11:03 +0100 Subject: [PATCH] use sqlite3 indexing for faster lookups attributes/references --- opcua/server/address_space_sqlite.py | 33 +++++++++++++++++----------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/opcua/server/address_space_sqlite.py b/opcua/server/address_space_sqlite.py index 3888e8ac4..df919dcea 100644 --- a/opcua/server/address_space_sqlite.py +++ b/opcua/server/address_space_sqlite.py @@ -86,6 +86,7 @@ class AddressSpaceSQLite(AddressSpace): Intended for slow devices, such as Raspberry Pi, to greatly improve start up time """ PY2 = sys.version_info < (3, 0) + NODEID_COL_NAME = 'NodeId' ATTR_TABLE_NAME = 'Attributes' REFS_TABLE_NAME = 'References' CUR_TIME_NODEID = NumericNodeId(ua.ObjectIds.Server_ServerStatus_CurrentTime, 0) @@ -296,9 +297,10 @@ def CB(row): # Read and write from attribute table @staticmethod def _create_attr_table(backend, table=ATTR_TABLE_NAME, drop=False): - ATTR_TABLE_COLS = [ + nid = AddressSpaceSQLite.NODEID_COL_NAME + ATTR_COLS = [ '_Id BLOB PRIMARY KEY NOT NULL', # 0 - 'NodeId BLOB', # 1 + '{:s} BLOB'.format(nid), # 1 'AttributeId INTEGER', # 2 'ServerTimestamp TIMESTAMP', # 3 'ServerPicoseconds INTEGER', # 4 @@ -308,11 +310,19 @@ def _create_attr_table(backend, table=ATTR_TABLE_NAME, drop=False): 'Variant BLOB', # 8 'Description STRING', # 9 ] + AddressSpaceSQLite._create_indexed_table(backend, table, ATTR_COLS, drop) + + @staticmethod + def _create_indexed_table(backend, table, cols, drop): + nid = AddressSpaceSQLite.NODEID_COL_NAME + cmds = [] if drop is True: - dropCmd = 'DROP TABLE IF EXISTS "{tn}"'.format(tn=table) - backend.execute_write(dropCmd, commit=True) - cmd = 'CREATE TABLE IF NOT EXISTS "{tn}" ({c})'.format(tn=table, c=', '.join(ATTR_TABLE_COLS)) - backend.execute_write(cmd, commit=True) + cmds.append('DROP INDEX IF EXISTS "idx_{tn}"'.format(tn=table)) + cmds.append('DROP TABLE IF EXISTS "{tn}"'.format(tn=table)) + cmds.append('CREATE TABLE IF NOT EXISTS "{tn}" ({c})'.format(tn=table, c=', '.join(cols))) + cmds.append('CREATE INDEX IF NOT EXISTS "idx_{tn}" ON "{tn}" ({nid})'.format(tn=table, nid=nid)) + for cmd in cmds: + backend.execute_write(cmd, commit=True) def _insert_attribute_threadsafe(self, nodeid, attrId, attr, table=ATTR_TABLE_NAME, commit=True): with self._lock: @@ -384,9 +394,10 @@ def _read_attribute_row(row): # Read and write from references table @staticmethod def _create_refs_table(backend, table=REFS_TABLE_NAME, drop=False): - REFS_TABLE_COLS = [ + nid = AddressSpaceSQLite.NODEID_COL_NAME + REFS_COLS = [ '_Id BLOB PRIMARY KEY NOT NULL', # 0 - 'NodeId BLOB', # 1 = the nodeid of this ReferenceDescription + '{:s} BLOB'.format(nid), # 1 = the nodeid of this ReferenceDescription 'ReferenceTypeId BLOB', # 2 'IsForward INTEGER', # 3 'ReferredNodeId BLOB', # 4 = referred nodeid of ReferenceDescription @@ -399,11 +410,7 @@ def _create_refs_table(backend, table=REFS_TABLE_NAME, drop=False): 'TypeDefinition BLOB', # 11 'Description STRING' # 12 ] - if drop is True: - dropCmd = 'DROP TABLE IF EXISTS "{tn}"'.format(tn=table) - backend.execute_write(dropCmd, commit=True) - cmd = 'CREATE TABLE IF NOT EXISTS "{tn}" ({c})'.format(tn=table, c=', '.join(REFS_TABLE_COLS)) - backend.execute_write(cmd, commit=True) + AddressSpaceSQLite._create_indexed_table(backend, table, REFS_COLS, drop) def _insert_reference_threadsafe(self, nodeid, ref, table=REFS_TABLE_NAME, commit=True): with self._lock: