Pourquoi :la mémoire: en sqlite-elle si lente?
J'ai essayé de voir s'il y a des améliorations des performances obtenues en utilisant sqlite en mémoire vs disque de base sqlite. Fondamentalement, je voudrais échanger les temps de démarrage et de mémoire pour obtenir extrêmement rapide des requêtes qui ne sont pas touchés de disque au cours de l'application.
Toutefois, la référence ci-après donne-moi seulement un facteur de 1,5 X à l'amélioration de la vitesse. Ici, je suis de la génération 1M de lignes de données aléatoires et de le charger dans un disque et de la mémoire en fonction de la version de la même table. Je puis exécutez aléatoire des requêtes sur les deux dbs, le retour des ensembles de taille environ 300k. Je m'attendais à la mémoire en fonction de la version à être beaucoup plus rapide, mais comme je le disais, je suis en obtenant seulement 1,5 X la vitesse.
J'ai expérimenté avec plusieurs autres dimensions de la bd et de la requête ensembles; l'avantage de :mémoire: ne semble aller comme le nombre de lignes dans la base de données augmente. Je ne suis pas sûr pourquoi, l'avantage est si petit, si j'ai eu quelques hypothèses:
- la table utilisée n'est pas assez grand (en lignes) à faire :mémoire: le grand vainqueur
- plus les jointures de tables et rendrait le :mémoire: avantage plus apparente
- il y a une sorte de mise en cache de passe à la connexion ou au niveau de l'OS, tels que les résultats précédents sont accessibles en quelque sorte, la corruption de l'indice de référence
- il y a une sorte de caché l'accès au disque passe que je ne vois pas (je n'ai pas essayé de lsof encore, mais je n'ai désactiver les PRAGMAs pour la journalisation)
Suis-je en train de faire quelque chose de mal ici? Toute réflexion sur la raison d'être :la mémoire n'est pas la production de quasi-instantané des recherches? Voici la référence:
==> sqlite_memory_vs_disk_benchmark.py <==
#!/usr/bin/env python
"""Attempt to see whether :memory: offers significant performance benefits.
"""
import os
import time
import sqlite3
import numpy as np
def load_mat(conn,mat):
c = conn.cursor()
#Try to avoid hitting disk, trading safety for speed.
#http://stackoverflow.com/questions/304393
c.execute('PRAGMA temp_store=MEMORY;')
c.execute('PRAGMA journal_mode=MEMORY;')
# Make a demo table
c.execute('create table if not exists demo (id1 int, id2 int, val real);')
c.execute('create index id1_index on demo (id1);')
c.execute('create index id2_index on demo (id2);')
for row in mat:
c.execute('insert into demo values(?,?,?);', (row[0],row[1],row[2]))
conn.commit()
def querytime(conn,query):
start = time.time()
foo = conn.execute(query).fetchall()
diff = time.time() - start
return diff
#1) Build some fake data with 3 columns: int, int, float
nn = 1000000 #numrows
cmax = 700 #num uniques in 1st col
gmax = 5000 #num uniques in 2nd col
mat = np.zeros((nn,3),dtype='object')
mat[:,0] = np.random.randint(0,cmax,nn)
mat[:,1] = np.random.randint(0,gmax,nn)
mat[:,2] = np.random.uniform(0,1,nn)
#2) Load it into both dbs & build indices
try: os.unlink('foo.sqlite')
except OSError: pass
conn_mem = sqlite3.connect(":memory:")
conn_disk = sqlite3.connect('foo.sqlite')
load_mat(conn_mem,mat)
load_mat(conn_disk,mat)
del mat
#3) Execute a series of random queries and see how long it takes each of these
numqs = 10
numqrows = 300000 #max number of ids of each kind
results = np.zeros((numqs,3))
for qq in range(numqs):
qsize = np.random.randint(1,numqrows,1)
id1a = np.sort(np.random.permutation(np.arange(cmax))[0:qsize]) #ensure uniqueness of ids queried
id2a = np.sort(np.random.permutation(np.arange(gmax))[0:qsize])
id1s = ','.join([str(xx) for xx in id1a])
id2s = ','.join([str(xx) for xx in id2a])
query = 'select * from demo where id1 in (%s) AND id2 in (%s);' % (id1s,id2s)
results[qq,0] = round(querytime(conn_disk,query),4)
results[qq,1] = round(querytime(conn_mem,query),4)
results[qq,2] = int(qsize)
#4) Now look at the results
print " disk | memory | qsize"
print "-----------------------"
for row in results:
print "%.4f | %.4f | %d" % (row[0],row[1],row[2])
Voici les résultats. Notez que le disque prend environ 1,5 X aussi longtemps que la mémoire d'un éventail assez large de requête tailles.
[ramanujan:~]$python -OO sqlite_memory_vs_disk_clean.py
disk | memory | qsize
-----------------------
9.0332 | 6.8100 | 12630
9.0905 | 6.6953 | 5894
9.0078 | 6.8384 | 17798
9.1179 | 6.7673 | 60850
9.0629 | 6.8355 | 94854
8.9688 | 6.8093 | 17940
9.0785 | 6.6993 | 58003
9.0309 | 6.8257 | 85663
9.1423 | 6.7411 | 66047
9.1814 | 6.9794 | 11345
Ne devrait pas RAM être presque instantanée par rapport à un disque? Ce qui ne va pas ici?
Modifier
Quelques bonnes suggestions ici.
Je suppose que le principal revenu net point pour moi, c'est que **il n'y a probablement pas de façon de faire :mémoire: absolument plus rapide, mais il y a une façon de faire de l'accès au disque relativement plus lente. **
En d'autres termes, l'indice de référence est suffisamment mesurer de façon réaliste les performances de la mémoire, mais pas de façon réaliste les performances de disque (par exemple, parce que le cache_size pragma est trop grand, ou parce que je ne fais pas écrit). Je vais déconner avec ces paramètres et d'après mes constatations, quand je reçois une chance.
Cela dit, si il y a quelqu'un qui pense que je peux le serrer quelques plus de vitesse de la mémoire db (autres que par le calage de la cache_size et default_cache_size, ce que je vais faire), je suis tout ouïe...