LINUX.ORG.RU

помогите оптимизировать sql-запрос


0

1

Здравствуйте, друзья.

Есть такая задача:

- имеем список строк (10-30 символов) - и имеем таблицу в БД sqlite, такой структуры: int uid, string строка, int фейлы

алгоритм такой: - получили строки - внесли их в БД, uid по умолчанию null, фейлы - по умолчанию 0 - обрабатываем строки - те строки, с которыми произошла ошибка - обновляются в БД, инкрементируется счетчик фейлов - все удачно обработанные строки получают свой уникальный uid, чтобы потом их повторно не обрабатывать

таблица нужна затем, чтобы запоминать и отсеивать впоследствии те строки, у которых 5 фейлов и больше а также те, которые были обработаны ранее (имеют uid)

проблема у меня на том месте, где мы получили строки и пытаемся из них удалить те, что в базе имеют по 5 фейлов

я сделал это так:

select data from rows where data in (перечисляем все строки через запятую) and fails >= 5 or uid is not null

т.е. достаем строки, которые в (перечисляем все имеющиеся в начале скрипта строки) и без ошибок, либо уже есть uid

соотв. потом из начального списка удаляем весь этот мусор а оставшиеся обрабатываем

1 список строк в запросе порой получается огромным 2 это неистово жрет память (python3, apache, sqlite3)

как по вашему будет правильнее удалить из начального списка все строки, имеющие фейлы и имеющие ИД, так чтобы не доставать всю таблицу (она может содержать миллионы строк)?

можно проверять каждую строку отдельным запросом, но не сожрет ли это все ресурсы?

> 1 список строк в запросе порой получается огромным 2 это неистово жрет память (python3, apache, sqlite3)

Делать подзапрос, а не просто перечислять. И огромный это сколько?

anonymous
()
create table emails(
    id int not null primary key,
    address varchar(30),
    sent bool,
    failcount int default 0
);

create unique index emails_address on emails(address);

create table task(email varchar(30));

insert into task values ('email1'); // Поместить вот так все строки ...
...
insert into task values('emailN'); // ... которые хотим обработать в этот цикл

foreach line in (
   select emails.* from tasks
   join emails
     on email.address = tasks.email and failcount < 5 and sent = 0
) {
   if (spame_sent(line["address"]) {
        update emails set failcount = failcount+1 where id = line["id"];
   } else {
        update emails set proceeded=1 where id = line["id"];
   }
}

/thread

no-dashi ★★★★★
()
Ответ на: комментарий от anonymous

>>Делать подзапрос, а не просто перечислять

не понимаю, какой подзапрос?

И огромный это сколько?


заранее неизвестно. но вполне может быть и 6000 символов
главное что это точно сжирает память

sergey-novikov ★★★
() автор топика

во первых «перечисляем все строки через запятую» корявит скорость. Если не нужен поиск по подстрокам(а только сравнения равно/не-равно), то можно дополнительно положить в базу хеш от строк и их сравнивать и индексировать (для sqlite совершенно точно).

во вторых вариант с доп.таблицей уже предложен и работать должен шустро.

если доп.таблица не подходит по идеалогии, то переложите часть работы на приложение; «where data in (...)» на прикладных хеш-таблицах в некоторых случаях эффективнее.

MKuznetsov ★★★★★
()

Сделай столбец со строкой индексированный. и для каждой строки из файла делай select * from rows where str=$str and fails > 5

Не забывай открывать тразакцию sqlite сразу после открытия файла, а закрывай её после (или перед..) закрытием файла. Если этого не делать - то транзакция открывается и закрывается на каждый стейтмент.

И да, используй prepare/execute

Будет ОЧЕНЬ быстро.

mmarkk
()
Ответ на: комментарий от MKuznetsov

класть в базу хеш - не очень хорошее решение. эскулайт и сам справится с этой задачей когда будет делать индекс.

Сравнение равно-неравно чисто по хешу не может дать точный результат из-за потенциальных коллизий хеша.

mmarkk
()
Ответ на: комментарий от mmarkk

Сравнение равно-неравно чисто по хешу не может дать точный результат из-за потенциальных коллизий хеша.

смотри

переложите часть работы на приложение; «where data in (...)» на прикладных хеш-таблицах

то есть на прикладе гипотетически возможные коллизии разруливаются очень быстро.

хотя штука тонкая, без понятия что там у ТС за база (объёмы/запросы/варианты использования) дать 100% рецепт невозможно. Более чем вероятно что те строки что ТС сравнивает можно легко класть в отдельную таблицу и оперировать их индексами.

эскулайт и сам справится с этой задачей когда будет делать индекс

заранее просчитанные хеши/свёртки работают быстрее. Хотя и могут приводить к коллизиям.

MKuznetsov ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.