Wydajność SQLite w projektach Django

Baza danych SQLite jest szybka przy odczytywaniu danych lecz powolna przy zapisie, jednakże oferuje kilka opcji, dzięki którym można znacząco podnieść wydajność. Opcje te opisane są w artykule Optymalizacja SQLite w Bibliotece PHP. W niniejszym artykule wykorzystamy kilka z nich w Django do zoptymalizowania wydajności bazy danych.

Testowy skrypt

# -*- coding: utf-8 -*-
from os import environ
environ['DJANGO_SETTINGS_MODULE'] = 'settings'
from settings import *

data = '''Slackware Linux 12.0 has been released: "Well folks, it's that time to announce a new stable Slackware release again. So, without further ado, announcing Slackware version 12.0!
Since we've moved to supporting the 2.6 kernel series exclusively (and fine-tuned the system to get the most out of it), we feel that Slackware 12.0 has many improvements over our last release and is a
 must-have upgrade for any Slackware user. Here are some of the advanced features of Slackware 12.0: runs the 2.6.21.5 version of the Linux kernel; system binaries are linked with the GNU C Library,
  version 2.5; X11 7.2.0; Apache 2.2.4 web server with Dynamic Shared Object support, SSL, and PHP 5.2.3; the udev dynamic device management system; updated versions of the Slackware package
   management tools...." Read the rest of the release announcement for full details. The CD and DVD images should be available from Slackware's FTP/HTTP mirrors in a few days; in the meantime get the new
    Slack via BitTorrent: slackware-12.0-install-dvd.iso (3,714MB).'''

from pages.models import *
Page.objects.all().delete()
for i in range(0,10):
	p = Page(title='test title' + str(i), slug='test-slug' + str(i), description='a sample description of an article bla foo bar', text=data)
	p.save()
	print str(i) + ' entry saved'
Powyższy skrypt umieściłem w katalogu z moim projektem Django zawierającym aplikację "Pages" z modelem "Page". Powyższy skrypt doda 10 wpisów do tabeli "Page". Czas wykonywania się skryptu mierzyłem za pomocą time:
time python test.py
By dodać omawiane w artykule polecenia zmieniające konfigurację SQLite należy wykonać własne zapytania. Przed zmienną "data" wstawiłem następujący kod:
from django.db import connection
cursor = connection.cursor()
#cursor.execute('PRAGMA temp_store = MEMORY;')
#cursor.execute('PRAGMA synchronous=OFF')
Co umożliwiło mi porównanie wpływu zmiany dwóch opcji. Plik bazy SQLite umieszczony był na partycji XFS pod kontrolą Gentoo Linux z kernelem 2.6.21.
  • Bez modyfikacji - 1.915 sekundy
  • PRAGMA synchronous=OFF - 0,783 sekundy
  • PRAGMA temp_store = MEMORY - 1,842 sekundy
  • Oba ustawienia - 0,764 sekundy
Wyłączenie trybu synchronicznego (PRAGMA synchronous=OFF) znacząco zwiększyło szybkość skryptu.

Następnie dla 100 rekordów w bazie danych zastosowałem taki kod:
from pages.models import *
for i in range(0,10):
	s1 = Page.objects.all()
	print len(s1)
	s1 = Page.objects.filter(id__gt=40)
	print len(s1)
Zmiana wspomnianych parametrów nie miała wpływu na czas wykonywania się skryptu (0,76 sek).

Jako ostatnie do przetestowania zostały zapytania update (dla 100 rekordów w tabeli):
p = Page.objects.all()
for i in p:
	i.description = 'a test sentence to check out sqlite performance'
	i.save()
  • Bez modyfikacji - 12.567 sekundy
  • Oba ustawienia - 2,032 sekundy
Różnica bardzo wyraźna. W czasie przeprowadzania testów nie zaobserwowano żadnych efektów ubocznych. Dla tego samego kodu sprawdzono szybkość skryptu po umieszczeniu bazy SQLite w pamięci RAM:
mount -t tmpfs tmpfs katalog
Plik bazy został przeniesiony do tego katalogu (RAM). Otrzymane wyniki porównano z pomiarem dla bazy SQLite umieszczonej na partycji EXT3.
  • Partycja XFS - 12.567 sekundy
  • Partycja EXT3 - 1,215 sekundy
  • Partycja EXT3, oba ustawienia - 0,620 sekundy
  • RAM - 0,611 sekundy
Powyższe dane ukazują jak wydajność systemu pliku wpływa na wydajność bazy SQLite w przypadku operacji zapisu. XFS nie jest szybkim systemem plików w porównaniu do EXT3, który to przy asynchronicznych operacjach jest praktycznie tak samo szybki jak operacje wykonywane w pamięci RAM.

Zmiana ustawień SQLite w aplikacji Django

Kod możemy umieścić np. w middleware:
class sqliteSettings(object):
	def process_request(self, request):
		from django.db import connection
		cursor = connection.cursor()
		cursor.execute('PRAGMA temp_store = MEMORY;')
		cursor.execute('PRAGMA synchronous=OFF')
RkBlog

Django, 14 July 2008

Comment article
Comment article RkBlog main page Search RSS Contact