Allow creating index concurrently

This commit is contained in:
Nicolas Évrard
2023-09-27 17:20:20 +02:00
parent 9ef3a0aafa
commit 75d1af9f84
7 changed files with 34 additions and 13 deletions
+1
View File
@@ -1,3 +1,4 @@
* Allow creating indexes concurrently
* Allow skipping index creation
* Add assert methods to test tools
* Set ELLIPSIS option flag on doctest
+4 -1
View File
@@ -304,11 +304,14 @@ TableHandler
Drop the named ``ident`` constraint.
``table`` can be used to alter another table.
.. method:: TableHandler.set_indexes(indexes)
.. method:: TableHandler.set_indexes(indexes[, concurrently])
Create the :class:`indexes <trytond.model.Index>` if possible and drop
others having ``idx_`` as prefix or ``_index`` as suffix.
If ``concurrently`` is set indexes are created concurrently if possible.
It defaults to ``False``.
.. method:: TableHandler.drop_column(column_name)
Drop the named column.
+13 -2
View File
@@ -494,7 +494,7 @@ class TableHandler(TableHandlerInterface):
Identifier(self.table_name), Identifier(ident)))
self._update_definitions(constraints=True)
def set_indexes(self, indexes):
def set_indexes(self, indexes, concurrently=False):
cursor = Transaction().connection.cursor()
old = set(self._indexes)
for index in indexes:
@@ -504,7 +504,18 @@ class TableHandler(TableHandlerInterface):
name = '_'.join([self.table_name, name])
name = 'idx_' + self.convert_name(name, reserved=len('idx_'))
cursor.execute(
SQL('CREATE INDEX IF NOT EXISTS {} ON {} USING {}').format(
'SELECT idx.indisvalid '
'FROM pg_index idx '
'JOIN pg_class cls ON cls.oid = idx.indexrelid '
'WHERE cls.relname = %s',
(name,))
if (idx_valid := cursor.fetchone()) and not idx_valid[0]:
cursor.execute(
SQL("DROP INDEX {}").format(Identifier(name)))
cursor.execute(
SQL('CREATE INDEX {} IF NOT EXISTS {} ON {} USING {}')
.format(
SQL('CONCURRENTLY' if concurrently else ''),
Identifier(name),
Identifier(self.table_name),
query),
+1 -1
View File
@@ -278,7 +278,7 @@ class TableHandler(TableHandlerInterface):
def drop_constraint(self, ident, table=None):
warnings.warn('Unable to drop constraint with SQLite backend')
def set_indexes(self, indexes):
def set_indexes(self, indexes, concurrently=False):
cursor = Transaction().connection.cursor()
old = set(self._indexes)
for index in indexes:
+1 -1
View File
@@ -107,7 +107,7 @@ class TableHandlerInterface(object):
name = hashlib.sha256(name).hexdigest()[:length - 1]
return name
def set_indexes(self, indexes):
def set_indexes(self, indexes, concurrently=False):
raise NotImplementedError
def index_translator_for(self, index):
+3 -3
View File
@@ -516,7 +516,7 @@ class ModelSQL(ModelStorage):
[h_table.write_date], [None]))
@classmethod
def _update_sql_indexes(cls):
def _update_sql_indexes(cls, concurrently=False):
def no_subset(index):
for j in cls._sql_indexes:
if j != index and index < j:
@@ -525,11 +525,11 @@ class ModelSQL(ModelStorage):
if not callable(cls.table_query):
table_h = cls.__table_handler__()
indexes = filter(no_subset, cls._sql_indexes)
table_h.set_indexes(indexes)
table_h.set_indexes(indexes, concurrently=concurrently)
if cls._history:
history_th = cls.__table_handler__(history=True)
indexes = filter(no_subset, cls._history_sql_indexes)
history_th.set_indexes(indexes)
history_th.set_indexes(indexes, concurrently=concurrently)
@classmethod
def _update_history_table(cls):
+11 -5
View File
@@ -246,13 +246,16 @@ def load_module_graph(graph, pool, update=None, lang=None, indexes=True):
pool.setup_mixin()
def create_indexes(concurrently):
for model_name in models_with_indexes:
model = pool.get(model_name)
if model._sql_indexes:
logger.info('index:update %s', model_name)
model._update_sql_indexes(concurrently=concurrently)
if update:
if indexes:
for model_name in models_with_indexes:
model = pool.get(model_name)
if model._sql_indexes:
logger.info('index:create %s', model_name)
model._update_sql_indexes()
create_indexes(concurrently=False)
transaction.commit()
else:
logger.info('index:skipping indexes creation')
@@ -262,6 +265,9 @@ def load_module_graph(graph, pool, update=None, lang=None, indexes=True):
logger.info('history:update %s', model.__name__)
model._update_history_table()
transaction.commit()
elif indexes:
with transaction.new_transaction(autocommit=True):
create_indexes(concurrently=True)
# Vacuum :
while modules_todo: