Самый эффективный способ выполнить SQL «INSERT IF NOT EXISTS»,

Какое из следующего будет работать лучше?

(1) **INSERT IGNORE** cursor.execute('INSERT IGNORE INTO table VALUES (%s,%s)') (2) **SELECT or CREATE** cursor.execute('SELECT 1 FROM table WHERE id=%s') if not cursor.fetchone(): cursor.execute('INSERT INTO table VALUES (%s,%s)') 

Я должен сделать это за миллионы раз, поэтому я ищу, чтобы найти лучшую производительность для этого шаблона. Какой из них предпочтительнее? Зачем?

3 Solutions collect form web for “Самый эффективный способ выполнить SQL «INSERT IF NOT EXISTS»,”

insert ignore является лучшим методом по нескольким причинам.

Что касается производительности, то только один запрос компилируется и выполняется, а не два. Это экономит накладные расходы на перемещение материала в базу данных и из нее.

Что касается обслуживания, то только один запрос более удобен в обслуживании, потому что логика находится в одном месте. Например, если вы добавили предложение where , вы, скорее всего, пропустите добавление его в два отдельных запроса.

С точки зрения точности, только один запрос не должен иметь (или, по крайней мере, намного меньше) возможностей для условий гонки. Если между insert и insert вставлена ​​строка, вы все равно получите ошибку.

Однако лучше, чем insert ignore insert . . . on duplicate key update является insert . . . on duplicate key update insert . . . on duplicate key update insert . . . on duplicate key update . Последний исключает ошибку для проблем дублирования. insert ignore может игнорировать ошибки, которые вам действительно нужны.

Кстати, вы должны все равно проверять ошибки из инструкции.

С большинством проблем с производительностью наилучшим подходом является попытка попробовать оба способа и измерить их, чтобы увидеть, что на самом деле быстрее. Большую часть времени есть много мелких вещей, которые влияют на производительность, которая не очевидна на поверхности. Попытка предсказать эффективность чего-то впереди часто занимает больше времени, чем проведение теста, и даже с невозможностью сделать это невозможно.

Важно, однако, быть максимально осторожным, чтобы точно имитировать ваши фактические условия производства. Как я уже говорил, небольшие вещи могут существенно повлиять на производительность, и вы захотите избежать недействительности теста, изменив один из них между тестовой средой и рабочей средой.

При производительности SQL одним из наиболее релевантных элементов является содержимое базы данных во время теста. Запросы, которые хорошо работают с несколькими строками, становятся очень медленными со многими строками. Или запросы, которые бывают быстрыми, когда все данные очень похожи, становятся очень медленными, когда они очень разнообразны. Наилучший подход (если это возможно) заключается в создании клона вашей производственной базы данных, в которой можно запускать тесты. Таким образом, вы уверены, что не обманываете себя неточной средой тестирования.

После того, как вы проверите свои тесты, вы можете запустить explain plan своей базы, чтобы точно узнать, что происходит с каждым подходом. Это часто позволит вам начать настройку как для устранения очевидных проблем. Иногда это будет иметь большое значение для изменения, которое быстрее или даже предлагает третий подход, который превосходит их обоих.

Для одного или нескольких записей я бы без всяких сомнений использовал первый подход «INSERT IGNORE».

Мы не знаем много подробностей о вашем случае, но в случае, если у вас есть объемные вставки (поскольку вы упомянули, что вам нужно запустить эти миллионы раз), тогда ключ для загрузки вашей производительности вставки – это использование 1 вставки для большинства вместо записи вставки для каждой записи.

Это может быть достигнуто либо:

  1. Использование INSERT IGNORE.

    INSERT IGNORE В таблицы VALUES (id1, 'val1'), (id2, 'val2') ….

  2. Или, что вы можете сделать, это сделать один оператор select, который для большого количества записей получает существующие записи, то есть: SELECT id FROM table WHERE id in (id1, id2, id3 ….) Затем программно, в вашем коде , исключить из первоначального списка те, которые получены из db. Затем запустите инструкцию INSERT:

    INSERT INTO таблицы VALUES (id1, 'val1'), (id5, 'val5') ..

Обычно мы ожидаем, что вставки INSERT IGNORE Bulk будут оптимальными, поскольку они обрабатываются движком db, но это не может быть гарантией. Поэтому для вашего решения лучше выполнить небольшую проверку для обоих случаев, используя большую часть данных.

Если вы не хотите запускать небольшой сравнительный тест для проверки, вы можете использовать встроенные вставки INSERT IGNORE (это необходимо в обоих случаях) во время теста, если вы заметили замедленность, вы можете попробовать второй подход.

Как правило, второй подход будет быстрым, так как первый выбор выполняется для большей части идентификаторов (pk), поэтому запрос выполняется быстро и намного лучше, чем запуск выбора для каждой записи. Инициализация идентификаторов программно также выполняется быстро.

  • Присоединение к подзапросу в SQLAlchemy
  • Pyspark: добавьте среднее значение в качестве нового столбца в DataFrame
  • Django, ManyToManyField - ProgrammingError: отношение foo_bar не существует. Признается в миграциях, хотя отношение никогда не создается
  • Вставка pyodbc в sql
  • Почему slowmany замедляется в Python MySQLdb?
  • Как использовать Pandas Write_Frame для экспорта результатов в Oracle Database в cx_Oracle
  • как безопасно генерировать инструкцию SQL LIKE с помощью python db-api
  • Django: сводные данные
  • Python - лучший язык программирования в мире.