Тестируем ZODB на скорость
В статье приводится сравнение по скорости ZODB и MySQL, результаты получились, в принципе, вполне ожидаемые. Но, все-таки,\ приятно, что и в ZODB можно вставить один миллион объектов...
Сравнительное тестирование MySQL и ZODB :
Недавно в пылу полемики в одной рассылке, наш оппонент выдвинул тезис вроде такого: "ZODB это вообще не база данных, потому что в ней нельзя сохранить один миллион записей, как в MySQL". Оставив на совести оппонента определение базы данных, как того, в чем можно сохранить один миллион записей, я призадумался: "А все-таки, насколько ZODB проигрывает по скорости MySQL?", - и провел соответствующие исследования.
До того, как рассказать о результатах, замечу: ZODB и MySQL совершенно различные базы данных как по целям применения, так и по стоящей за ними модели данных:
-- ZODB оптимизирована для редких операций записи и частых операций чтения, тогда как MySQL такой оптимизации не имеет;
-- ZODB база объектно-ориентированная, MySQL - реляционная. Соответственно, в реальных условиях ZODB никогда не будет иметь такого режима работы, как MySQL, впрочем, обратное тоже верно.
Приводимый ниже тест носит поверхностный характер и борьба происходит скорее на поле MySQL, чем на поле ZODB: мы просто тестируем хранилище на скорость записи и извлечения табличных данных.
Результаты:
Для тестирования использовались:
MySQL версии 5.0.27
Zope версии 3.3.0
Вставка 1000000 записей в ZODB:
Затрачено времени: 3 часа 48 минут.
Средняя скорость вставки: 71 запись в секунду.
Длительность переупаковки базы: 3 минуты.
Объем базы: 889М до упаковки и 29М после.
Вставка 1000000 записей в MySQL:
Затрачено времени: 2 минуты
Средняя скорость вставки: 8928 записей в секунду.
Объем базы: 37М
Чтение из ZODB:
Затрачено времени: 2 минуты
Средняя скорость чтения: 7194 записей в секунду.
Чтение из MySQL:
Затрачено времени: 5 минут
Средняя скорость чтения: 3278 записей в секунду.
Заключение:
Как можно видеть, ZODB действительно притормаживает на операциях вставки (практически на два порядка), и несущественно обгоняет MySQL на операциях извлечения данных. Поэтому, использование ZODB как хранилища архивов вполне оправдано, для чего она собственно и разрабатывалась.
Впрочем, серьезное тестирование не проводилось :), поэтому за точное количественное воспроизведение результатов я не поручусь: потому и характеристики железа не привожу, что бы соблазна не было. Кроме того, сами статистические характеристики теста далеки от той реальности, в которой работает ZODB.
А по относительным данным замечу еще вот что: любим мы ZODB не за скорость. А за траспарентность при работе с данными. К сожалению, по причине отсутствия соответствующих средств в MySQL, сравнивать их на этом поле я не могу. А было бы интересно :)
Приложение А : Исходники тестов
Скриптик для записи в MySQL:
#/usr/bin/python import MySQLdb import time con=MySQLdb.connect(db="test") con.autocommit(1) con.query("CREATE TABLE a(ak varchar(64), av varchar(64));") con.query("create index ai on a(ak);") t1 = t = time.time() for item in range(0,1000000) : if not item % 1000 : t2 = time.time() print item,t2-t1 t1 = t2 con.query("INSERT INTO a VALUES ('%s','%s');" % (item,item)) print "Time:",time.time()-t con.close() Скриптик для записи в ZODB:: #/usr/bin/python import ZODB import time from ZODB.FileStorage import FileStorage from BTrees.OOBTree import OOBTree d=ZODB.DB(FileStorage("/tmp/d.fs")) con=d.open() con.root()['btree'] = OOBTree() import transaction txn=transaction.get() txn.commit() t1 = t = time.time() for item in range(0,1000000) : if not item % 1000 : t2 = time.time() print item,t2-t1 t1 = t2 con.newTransaction() con.root()['btree'][str(item)] = str(item) txn=transaction.get() txn.commit() print "Time:",time.time()-t d.pack() print "Time:",time.time()-t con.close() d.close()
Скриптик для чтения MySQL:
#/usr/bin/python import MySQLdb import time con=MySQLdb.connect(db="test") con.autocommit(1) t1 = t = time.time() for item in range(0,1000000) : if not item % 1000 : t2 = time.time() print item,t2-t1 t1 = t2 cur=con.cursor() cur.execute("SELECT av FROM a WHERE ak='%s';" % item) cur.fetchall() print "Time:",time.time()-t con.close()
Скриптик для чтения ZODB:
#/usr/bin/python import ZODB import time from ZODB.FileStorage import FileStorage from BTrees.OOBTree import OOBTree d=ZODB.DB(FileStorage("/tmp/d.fs")) con=d.open() import transaction txn=transaction.get() txn.commit() t1 = t = time.time() for item in range(0,1000000) : if not item % 1000 : t2 = time.time() print item,t2-t1 t1 = t2 con.newTransaction() a=con.root()['btree'][str(item)] txn=transaction.get() txn.commit() print "Time:",time.time()-t con.close() d.close()