2015-11-09 3 views
1

Я использую PyQt для программного обеспечения GUI. Я также использую базу данных sqlite для передачи программного обеспечения с данными.Является ли query.next() медленным?

Где-то в моем коде, у меня есть этот метод:

def loadNotifications(self): 

    """Method to find the number of unread articles, 
    for each search. Load a list of id, for the unread articles, 
    in each table. And a list of id, for the concerned articles, for 
    each table""" 

    count_query = QtSql.QSqlQuery(self.bdd) 
    count_query.setForwardOnly(True) 

    # Don't treat the articles if it's the main tab, it's 
    # useless because the article will be concerned for sure 
    for table in self.list_tables_in_tabs[1:]: 

     # Empty these lists, because when loadNotifications is called 
     # several times during the use, the nbr of unread articles is 
     # added to the nbr of notifications 
     table.list_new_ids = [] 
     table.list_id_articles = [] 

     # Try to speed things up 
     append_new = table.list_new_ids.append 
     append_articles = table.list_id_articles.append 

     req_str = self.refineBaseQuery(table.base_query, table.topic_entries, table.author_entries) 
     print(req_str) 
     count_query.exec_(req_str) 

     start_time = datetime.datetime.now() 
     i = 0 

     while count_query.next(): 
      i += 1 
      record = count_query.record() 

      append_articles(record.value('id')) 

      if record.value('new') == 1: 
       append_new(record.value('id')) 

     print(datetime.datetime.now() - start_time) 
     print("Nbr of entries processed: {}".format(i)) 

Давайте предположим, что этот цикл имеет ~ 400 записей для обработки. Это занимает около одной секунды, и я думаю, что это слишком долго. Я пытался оптимизировать процесс, насколько мог, но это занимает слишком много времени.

Вот что предыдущий метод обычно печатает:

SELECT * FROM papers WHERE id IN(320, 1320, 5648, 17589, 20092, 20990, 49439, 58378, 65251, 68772, 73509, 86859, 90594) 
0:00:00.001403 
Nbr of entries processed: 13 
SELECT * FROM papers WHERE topic_simple LIKE '% 3D print%' 
0:00:00.591745 
Nbr of entries processed: 81 
SELECT * FROM papers WHERE id IN (5648, 11903, 14258, 30587, 40339, 55691, 57383, 58378, 62951, 65251, 68772, 87295) 
0:00:00.000478 
Nbr of entries processed: 12 
SELECT * FROM papers WHERE topic_simple LIKE '% Python %' 
0:00:00.596490 
Nbr of entries processed: 9 
SELECT * FROM papers WHERE topic_simple LIKE '% Raspberry pi %' OR topic_simple LIKE '% arduino %' 
0:00:00.988276 
Nbr of entries processed: 5 
SELECT * FROM papers WHERE topic_simple LIKE '% sensor array%' OR topic_simple LIKE '% biosensor %' 
0:00:00.996164 
Nbr of entries processed: 433 
SELECT * FROM papers WHERE id IN (320, 540, 1320, 1434, 1860, 4527, 5989, 6022, 6725, 6978, 7268, 8625, 9410, 9814, 9850, 10608, 13219, 15572, 15794, 19345, 19674, 19899, 20990, 22530, 26443, 26535, 28721, 29089, 30923, 31145, 31458, 31598, 32069, 34129, 35820, 36142, 36435, 37546, 39188, 39952, 40949, 41764, 43529, 43610, 44184, 45206, 49210, 49807, 50279, 50943, 51536, 51549, 52921, 52967, 54610, 56036, 58087, 60490, 62133, 63051, 63480, 63535, 64861, 66906, 68107, 68328, 69021, 71797, 73058, 74974, 75331, 77697, 78138, 80152, 80539, 82172, 82370, 82840, 86859, 87467, 91528, 92167) 
0:00:00.002891 
Nbr of entries processed: 82 
SELECT * FROM papers WHERE id IN (7043, 41643, 44688, 50447, 64723, 72601, 81006, 82380, 84285) 
0:00:00.000348 
Nbr of entries processed: 9 

ли это лучше? Могу ли я получить лучшие результаты?

ПРИМЕЧАНИЕ. Отображаемое время - это время, необходимое для запуска цикла, а не время, необходимое для выполнения запроса.

Я пробовал count_query.setForwardOnly(True), как упоминалось в документе, но это не повлияло на функционал.

EDIT: Вот тестовая база данных с ~ 600 записей: database

ответ

1

Очевидно, что я не могу проверить это, так что я не знаю, если это будет иметь существенное значение, но вы можете попробовать использовать индекс -На взгляд окна:

id_index = count_query.record().indexOf('id') 
new_index = count_query.record().indexOf('new') 
while count_query.next(): 
    record = count_query.record() 
    id_value = record.value(id_index) 
    append_articles(id_value) 
    if record.value(new_index) == 1: 
     append_new(id_value) 

UPDATE:

Использование образца дб, я не могу воспроизвести проблему, вы видите, и я также наш метод выше примерно в два раза быстрее, чем ваш оригинал. Вот некоторые пример вывода:

IDs: 660, Articles: 666 
IDs: 660, Articles: 666 
IDs: 660, Articles: 666 
test(index=False): 0.19050272400090762 
IDs: 660, Articles: 666 
IDs: 660, Articles: 666 
IDs: 660, Articles: 666 
test(index=True): 0.09384496400161879 

Тестовый пример:

import sys, os, timeit 
from PyQt4 import QtCore, QtGui 
from PyQt4.QtSql import QSqlDatabase, QSqlQuery 

def test(index=False): 
    count_query = QSqlQuery('select * from results') 
    list_new_ids = [] 
    list_id_articles = [] 
    append_new = list_new_ids.append 
    append_articles = list_id_articles.append 
    if index: 
     id_index = count_query.record().indexOf('id') 
     new_index = count_query.record().indexOf('new') 
     while count_query.next(): 
      record = count_query.record() 
      id_value = record.value(id_index) 
      append_articles(id_value) 
      if record.value(new_index) == 1: 
       append_new(id_value) 
    else: 
     while count_query.next(): 
      record = count_query.record() 
      append_articles(record.value('id')) 
      if record.value('new') == 1: 
       append_new(record.value('id')) 
    print('IDs: %d, Articles: %d' % (
     len(list_new_ids), len(list_id_articles))) 

class Window(QtGui.QWidget): 
    def __init__(self): 
     super(Window, self).__init__() 
     self.button = QtGui.QPushButton('Test', self) 
     self.button.clicked.connect(self.handleButton) 
     layout = QtGui.QVBoxLayout(self) 
     layout.addWidget(self.button) 
     self.database = QSqlDatabase.addDatabase("QSQLITE") 
     path = os.path.join(os.path.dirname(__file__), 'tmp/perf-test.db') 
     self.database.setDatabaseName(path) 
     self.database.open() 

    def handleButton(self): 
     for stmt in 'test(index=False)', 'test(index=True)': 
      print('%s: %s' % (stmt, timeit.timeit(
       stmt, 'from __main__ import test', number=3))) 

if __name__ == '__main__': 

    import sys 
    app = QtGui.QApplication(sys.argv) 
    window = Window() 
    window.setGeometry(600, 300, 200, 100) 
    window.show() 
    sys.exit(app.exec_()) 
+0

Нету извините, ничего не изменилось. Перфорации были одинаковыми, цикл занимает почти ровно одно и то же время (он может быть немного менее хорошим, но я не думаю, что он статистически значим). – Rififi

+0

@ Рифифи. Думал, вы могли бы это сказать. Трудно делать полезные предложения без реальной выборки db для тестирования. – ekhumoro

+0

Да, я знаю, я подготовил тестовую базу данных, посмотрю мое редактирование. – Rififi

Смежные вопросы