Ускорьте вставку базы данных из ORM
-
05-07-2019 - |
Вопрос
У меня есть представление Django, которое в цикле создает 500-5000 новых вставок базы данных.Проблема в том, что это очень медленно!Я получаю около 100 вставок в минуту в Postgres 8.3.Раньше мы использовали MySQL на меньшем оборудовании (меньший экземпляр EC2) и никогда не сталкивались с такими проблемами со скоростью.
Подробности:Postgres 8.3 на сервере Ubuntu 9.04.Сервер представляет собой «большой» Amazon EC2 с базой данных на EBS (ext3) — 11ГБ/20ГБ.
Вот часть моего файла postgresql.conf — дайте мне знать, если вам нужно больше
shared_buffers = 4000MB
effective_cache_size = 7128MB
Мой питон:
for k in kw:
k = k.lower()
p = ProfileKeyword(profile=self)
logging.debug(k)
p.keyword, created = Keyword.objects.get_or_create(keyword=k, defaults={'keyword':k,})
if not created and ProfileKeyword.objects.filter(profile=self, keyword=p.keyword).count():
#checking created is just a small optimization to save some database hits on new keywords
pass #duplicate entry
else:
p.save()
Некоторые выводы сверху:
top - 16:56:22 up 21 days, 20:55, 4 users, load average: 0.99, 1.01, 0.94
Tasks: 68 total, 1 running, 67 sleeping, 0 stopped, 0 zombie
Cpu(s): 5.8%us, 0.2%sy, 0.0%ni, 90.5%id, 0.7%wa, 0.0%hi, 0.0%si, 2.8%st
Mem: 15736360k total, 12527788k used, 3208572k free, 332188k buffers
Swap: 0k total, 0k used, 0k free, 11322048k cached
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
14767 postgres 25 0 4164m 117m 114m S 22 0.8 2:52.00 postgres
1 root 20 0 4024 700 592 S 0 0.0 0:01.09 init
2 root RT 0 0 0 0 S 0 0.0 0:11.76 migration/0
3 root 34 19 0 0 0 S 0 0.0 0:00.00 ksoftirqd/0
4 root RT 0 0 0 0 S 0 0.0 0:00.00 watchdog/0
5 root 10 -5 0 0 0 S 0 0.0 0:00.08 events/0
6 root 11 -5 0 0 0 S 0 0.0 0:00.00 khelper
7 root 10 -5 0 0 0 S 0 0.0 0:00.00 kthread
9 root 10 -5 0 0 0 S 0 0.0 0:00.00 xenwatch
10 root 10 -5 0 0 0 S 0 0.0 0:00.00 xenbus
18 root RT -5 0 0 0 S 0 0.0 0:11.84 migration/1
19 root 34 19 0 0 0 S 0 0.0 0:00.01 ksoftirqd/1
Дайте мне знать, если какие-либо другие подробности будут полезны.
Решение
Во-первых, операции ORM всегда будут медленнее, чем чистый SQL.Однажды я написал обновление для большой базы данных в коде ORM и запустил его, но бросил его через несколько часов, когда оно завершило лишь небольшую часть.После переписывания его на SQL все прошло менее чем за минуту.
Во-вторых, имейте в виду, что ваш код выполняет до четырех отдельных операций с базой данных для каждой строки вашего набора данных. get
в get_or_create, возможно, также create
, count
на фильтре и, наконец, save
.Это большой доступ к базе данных.
Принимая во внимание, что максимум 5000 объектов — это не так уж и много, вы должны быть в состоянии прочитать весь набор данных в памяти с самого начала.Тогда вы можете сделать один filter
получить все существующие объекты ключевых слов за один раз, сохранив огромное количество запросов в ключевом слове get_or_create
а также избежать необходимости создавать дубликаты ProfileKeywords.
Другие советы
Одной из распространенных причин медленных массовых операций, подобных этой, является то, что каждая вставка происходит в отдельной транзакции.Если вы сможете заставить все это произойти за одну транзакцию, это может произойти намного быстрее.