RkBlog

Hardware, programming and astronomy tutorials and reviews.

Wydajność SQLite w projektach Django

Przegląd możliwych rozwiązań i ustawień wpływających na wydajność bazy SQLite. Artykuł pokazuje jak zastosować te optymalizacje w aplikacjach napisanych we frameworku 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. 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()
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. 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