Context manager to temporarily drop indexes and constraints on a table











up vote
0
down vote

favorite












I'm importing millions of rows into a PostgreSQL database using a foreign data wrapper. To speed this up I've written this context manager to DROP all the indexes and constraints (except the primary key) on the target table for the duration of the data move and reinstate them afterwards:



import logging
import types
import typing
from psycopg2 import _psycopg, sql


class RawTable():
def __init__(self, cursor: _psycopg.cursor, table_name: str, schema_name: str = 'public'):
self.cursor = cursor
self.schema_name = schema_name
self.table_name = table_name

self.constraints: typing.List[typing.Tuple[str, str]] =
self.index_definitions: typing.List[str] =

def __enter__(self) -> None:
self.store_and_delete_constraints()
self.store_and_delete_indexes()

def store_and_delete_constraints(self) -> None:
self.cursor.execute(
"""
SELECT pg_constraint.conname,
pg_get_constraintdef(pg_constraint.oid)
FROM pg_constraint
JOIN pg_class ON pg_constraint.conrelid = pg_class.oid
JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
WHERE pg_constraint.contype <> 'p' AND
pg_class.relname = %s AND
pg_namespace.nspname = %s
""",
(self.table_name, self.schema_name)
)
for (name, constraint_sql) in self.cursor.fetchall():
self.constraints.append((name, constraint_sql))
logging.debug("Dropping constraint {}".format(name))
self.cursor.execute(
sql.SQL('ALTER TABLE {}.{} DROP CONSTRAINT {}').format(
sql.Identifier(self.schema_name),
sql.Identifier(self.table_name),
sql.Identifier(name)
)
)

def store_and_delete_indexes(self) -> None:
self.cursor.execute(
"""
SELECT index_class.relname,
pg_get_indexdef(pg_index.indexrelid)
FROM pg_index
JOIN pg_class AS index_class ON pg_index.indexrelid = index_class.oid
JOIN pg_class AS table_class ON pg_index.indrelid = table_class.oid
JOIN pg_namespace ON pg_namespace.oid = index_class.relnamespace
WHERE NOT pg_index.indisprimary AND
pg_index.indisvalid AND
table_class.relname = %s AND
pg_namespace.nspname = %s
""",
(self.table_name, self.schema_name)
)
for (name, index_sql) in self.cursor.fetchall():
self.index_definitions.append(index_sql)
logging.debug("Dropping index {}".format(name))
self.cursor.execute(sql.SQL('DROP INDEX {}').format(sql.Identifier(name)))

def __exit__(
self,
exception_type: typing.Type[BaseException],
exception: BaseException,
traceback: types.TracebackType
) -> bool:
self.restore_constraints()
self.restore_indexes()
return exception_type is None

def restore_constraints(self) -> None:
logging.debug("Restoring {} constraint(s)".format(len(self.constraints)))
constraint_definitions = [
sql.SQL("ADD CONSTRAINT {} {}").format(
sql.Identifier(name),
sql.SQL(constraint_sql)
) for name, constraint_sql in self.constraints
]
self.cursor.execute(
sql.SQL("ALTER TABLE {}.{} {}").format(
sql.Identifier(self.schema_name),
sql.Identifier(self.table_name),
sql.SQL(', ').join(constraint_definitions)
)
)

def restore_indexes(self) -> None:
logging.debug("Restoring {} index(es)".format(len(self.index_definitions)))
for index_definition in self.index_definitions:
self.cursor.execute(index_definition)


Example use:



with connection.cursor() as cursor, RawTable(cursor, 'target_table'):
cursor.execute('INSERT INTO target_table SELECT … FROM huge_table')


(Log level is expected to be set up elsewhere, hence the lack of a logging.basicConfig or equivalent call.)









share


























    up vote
    0
    down vote

    favorite












    I'm importing millions of rows into a PostgreSQL database using a foreign data wrapper. To speed this up I've written this context manager to DROP all the indexes and constraints (except the primary key) on the target table for the duration of the data move and reinstate them afterwards:



    import logging
    import types
    import typing
    from psycopg2 import _psycopg, sql


    class RawTable():
    def __init__(self, cursor: _psycopg.cursor, table_name: str, schema_name: str = 'public'):
    self.cursor = cursor
    self.schema_name = schema_name
    self.table_name = table_name

    self.constraints: typing.List[typing.Tuple[str, str]] =
    self.index_definitions: typing.List[str] =

    def __enter__(self) -> None:
    self.store_and_delete_constraints()
    self.store_and_delete_indexes()

    def store_and_delete_constraints(self) -> None:
    self.cursor.execute(
    """
    SELECT pg_constraint.conname,
    pg_get_constraintdef(pg_constraint.oid)
    FROM pg_constraint
    JOIN pg_class ON pg_constraint.conrelid = pg_class.oid
    JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
    WHERE pg_constraint.contype <> 'p' AND
    pg_class.relname = %s AND
    pg_namespace.nspname = %s
    """,
    (self.table_name, self.schema_name)
    )
    for (name, constraint_sql) in self.cursor.fetchall():
    self.constraints.append((name, constraint_sql))
    logging.debug("Dropping constraint {}".format(name))
    self.cursor.execute(
    sql.SQL('ALTER TABLE {}.{} DROP CONSTRAINT {}').format(
    sql.Identifier(self.schema_name),
    sql.Identifier(self.table_name),
    sql.Identifier(name)
    )
    )

    def store_and_delete_indexes(self) -> None:
    self.cursor.execute(
    """
    SELECT index_class.relname,
    pg_get_indexdef(pg_index.indexrelid)
    FROM pg_index
    JOIN pg_class AS index_class ON pg_index.indexrelid = index_class.oid
    JOIN pg_class AS table_class ON pg_index.indrelid = table_class.oid
    JOIN pg_namespace ON pg_namespace.oid = index_class.relnamespace
    WHERE NOT pg_index.indisprimary AND
    pg_index.indisvalid AND
    table_class.relname = %s AND
    pg_namespace.nspname = %s
    """,
    (self.table_name, self.schema_name)
    )
    for (name, index_sql) in self.cursor.fetchall():
    self.index_definitions.append(index_sql)
    logging.debug("Dropping index {}".format(name))
    self.cursor.execute(sql.SQL('DROP INDEX {}').format(sql.Identifier(name)))

    def __exit__(
    self,
    exception_type: typing.Type[BaseException],
    exception: BaseException,
    traceback: types.TracebackType
    ) -> bool:
    self.restore_constraints()
    self.restore_indexes()
    return exception_type is None

    def restore_constraints(self) -> None:
    logging.debug("Restoring {} constraint(s)".format(len(self.constraints)))
    constraint_definitions = [
    sql.SQL("ADD CONSTRAINT {} {}").format(
    sql.Identifier(name),
    sql.SQL(constraint_sql)
    ) for name, constraint_sql in self.constraints
    ]
    self.cursor.execute(
    sql.SQL("ALTER TABLE {}.{} {}").format(
    sql.Identifier(self.schema_name),
    sql.Identifier(self.table_name),
    sql.SQL(', ').join(constraint_definitions)
    )
    )

    def restore_indexes(self) -> None:
    logging.debug("Restoring {} index(es)".format(len(self.index_definitions)))
    for index_definition in self.index_definitions:
    self.cursor.execute(index_definition)


    Example use:



    with connection.cursor() as cursor, RawTable(cursor, 'target_table'):
    cursor.execute('INSERT INTO target_table SELECT … FROM huge_table')


    (Log level is expected to be set up elsewhere, hence the lack of a logging.basicConfig or equivalent call.)









    share
























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I'm importing millions of rows into a PostgreSQL database using a foreign data wrapper. To speed this up I've written this context manager to DROP all the indexes and constraints (except the primary key) on the target table for the duration of the data move and reinstate them afterwards:



      import logging
      import types
      import typing
      from psycopg2 import _psycopg, sql


      class RawTable():
      def __init__(self, cursor: _psycopg.cursor, table_name: str, schema_name: str = 'public'):
      self.cursor = cursor
      self.schema_name = schema_name
      self.table_name = table_name

      self.constraints: typing.List[typing.Tuple[str, str]] =
      self.index_definitions: typing.List[str] =

      def __enter__(self) -> None:
      self.store_and_delete_constraints()
      self.store_and_delete_indexes()

      def store_and_delete_constraints(self) -> None:
      self.cursor.execute(
      """
      SELECT pg_constraint.conname,
      pg_get_constraintdef(pg_constraint.oid)
      FROM pg_constraint
      JOIN pg_class ON pg_constraint.conrelid = pg_class.oid
      JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
      WHERE pg_constraint.contype <> 'p' AND
      pg_class.relname = %s AND
      pg_namespace.nspname = %s
      """,
      (self.table_name, self.schema_name)
      )
      for (name, constraint_sql) in self.cursor.fetchall():
      self.constraints.append((name, constraint_sql))
      logging.debug("Dropping constraint {}".format(name))
      self.cursor.execute(
      sql.SQL('ALTER TABLE {}.{} DROP CONSTRAINT {}').format(
      sql.Identifier(self.schema_name),
      sql.Identifier(self.table_name),
      sql.Identifier(name)
      )
      )

      def store_and_delete_indexes(self) -> None:
      self.cursor.execute(
      """
      SELECT index_class.relname,
      pg_get_indexdef(pg_index.indexrelid)
      FROM pg_index
      JOIN pg_class AS index_class ON pg_index.indexrelid = index_class.oid
      JOIN pg_class AS table_class ON pg_index.indrelid = table_class.oid
      JOIN pg_namespace ON pg_namespace.oid = index_class.relnamespace
      WHERE NOT pg_index.indisprimary AND
      pg_index.indisvalid AND
      table_class.relname = %s AND
      pg_namespace.nspname = %s
      """,
      (self.table_name, self.schema_name)
      )
      for (name, index_sql) in self.cursor.fetchall():
      self.index_definitions.append(index_sql)
      logging.debug("Dropping index {}".format(name))
      self.cursor.execute(sql.SQL('DROP INDEX {}').format(sql.Identifier(name)))

      def __exit__(
      self,
      exception_type: typing.Type[BaseException],
      exception: BaseException,
      traceback: types.TracebackType
      ) -> bool:
      self.restore_constraints()
      self.restore_indexes()
      return exception_type is None

      def restore_constraints(self) -> None:
      logging.debug("Restoring {} constraint(s)".format(len(self.constraints)))
      constraint_definitions = [
      sql.SQL("ADD CONSTRAINT {} {}").format(
      sql.Identifier(name),
      sql.SQL(constraint_sql)
      ) for name, constraint_sql in self.constraints
      ]
      self.cursor.execute(
      sql.SQL("ALTER TABLE {}.{} {}").format(
      sql.Identifier(self.schema_name),
      sql.Identifier(self.table_name),
      sql.SQL(', ').join(constraint_definitions)
      )
      )

      def restore_indexes(self) -> None:
      logging.debug("Restoring {} index(es)".format(len(self.index_definitions)))
      for index_definition in self.index_definitions:
      self.cursor.execute(index_definition)


      Example use:



      with connection.cursor() as cursor, RawTable(cursor, 'target_table'):
      cursor.execute('INSERT INTO target_table SELECT … FROM huge_table')


      (Log level is expected to be set up elsewhere, hence the lack of a logging.basicConfig or equivalent call.)









      share













      I'm importing millions of rows into a PostgreSQL database using a foreign data wrapper. To speed this up I've written this context manager to DROP all the indexes and constraints (except the primary key) on the target table for the duration of the data move and reinstate them afterwards:



      import logging
      import types
      import typing
      from psycopg2 import _psycopg, sql


      class RawTable():
      def __init__(self, cursor: _psycopg.cursor, table_name: str, schema_name: str = 'public'):
      self.cursor = cursor
      self.schema_name = schema_name
      self.table_name = table_name

      self.constraints: typing.List[typing.Tuple[str, str]] =
      self.index_definitions: typing.List[str] =

      def __enter__(self) -> None:
      self.store_and_delete_constraints()
      self.store_and_delete_indexes()

      def store_and_delete_constraints(self) -> None:
      self.cursor.execute(
      """
      SELECT pg_constraint.conname,
      pg_get_constraintdef(pg_constraint.oid)
      FROM pg_constraint
      JOIN pg_class ON pg_constraint.conrelid = pg_class.oid
      JOIN pg_namespace ON pg_namespace.oid = pg_class.relnamespace
      WHERE pg_constraint.contype <> 'p' AND
      pg_class.relname = %s AND
      pg_namespace.nspname = %s
      """,
      (self.table_name, self.schema_name)
      )
      for (name, constraint_sql) in self.cursor.fetchall():
      self.constraints.append((name, constraint_sql))
      logging.debug("Dropping constraint {}".format(name))
      self.cursor.execute(
      sql.SQL('ALTER TABLE {}.{} DROP CONSTRAINT {}').format(
      sql.Identifier(self.schema_name),
      sql.Identifier(self.table_name),
      sql.Identifier(name)
      )
      )

      def store_and_delete_indexes(self) -> None:
      self.cursor.execute(
      """
      SELECT index_class.relname,
      pg_get_indexdef(pg_index.indexrelid)
      FROM pg_index
      JOIN pg_class AS index_class ON pg_index.indexrelid = index_class.oid
      JOIN pg_class AS table_class ON pg_index.indrelid = table_class.oid
      JOIN pg_namespace ON pg_namespace.oid = index_class.relnamespace
      WHERE NOT pg_index.indisprimary AND
      pg_index.indisvalid AND
      table_class.relname = %s AND
      pg_namespace.nspname = %s
      """,
      (self.table_name, self.schema_name)
      )
      for (name, index_sql) in self.cursor.fetchall():
      self.index_definitions.append(index_sql)
      logging.debug("Dropping index {}".format(name))
      self.cursor.execute(sql.SQL('DROP INDEX {}').format(sql.Identifier(name)))

      def __exit__(
      self,
      exception_type: typing.Type[BaseException],
      exception: BaseException,
      traceback: types.TracebackType
      ) -> bool:
      self.restore_constraints()
      self.restore_indexes()
      return exception_type is None

      def restore_constraints(self) -> None:
      logging.debug("Restoring {} constraint(s)".format(len(self.constraints)))
      constraint_definitions = [
      sql.SQL("ADD CONSTRAINT {} {}").format(
      sql.Identifier(name),
      sql.SQL(constraint_sql)
      ) for name, constraint_sql in self.constraints
      ]
      self.cursor.execute(
      sql.SQL("ALTER TABLE {}.{} {}").format(
      sql.Identifier(self.schema_name),
      sql.Identifier(self.table_name),
      sql.SQL(', ').join(constraint_definitions)
      )
      )

      def restore_indexes(self) -> None:
      logging.debug("Restoring {} index(es)".format(len(self.index_definitions)))
      for index_definition in self.index_definitions:
      self.cursor.execute(index_definition)


      Example use:



      with connection.cursor() as cursor, RawTable(cursor, 'target_table'):
      cursor.execute('INSERT INTO target_table SELECT … FROM huge_table')


      (Log level is expected to be set up elsewhere, hence the lack of a logging.basicConfig or equivalent call.)







      python python-3.x postgresql





      share












      share










      share



      share










      asked 1 min ago









      l0b0

      4,092923




      4,092923



























          active

          oldest

          votes











          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209126%2fcontext-manager-to-temporarily-drop-indexes-and-constraints-on-a-table%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown






























          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes
















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.





          Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


          Please pay close attention to the following guidance:


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f209126%2fcontext-manager-to-temporarily-drop-indexes-and-constraints-on-a-table%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          Ottavio Pratesi

          Tricia Helfer

          15 giugno