LINUX.ORG.RU

Отфильтровать массив строк, выбрав только хранящиеся в БД


0

1

Есть массив строк, необходимо узнать какие из них присутствуют в БД. Как это лучше делать, и кто с этим справится лучше всего?

Дополнение: в исходном массиве ~100..1000 строк. В базе ~100k..1kk

★★★★

Последнее исправление: special-k (всего исправлений: 1)

Загрузить во временную таблицу и сджойнить?

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

Никак еще. Я вот спрашиваю: что с этим справится лучше всего ( mysql, или, может redis, couchdb и т.д). Т.е. технология + методика применения.

пс А вообще, склоняюсь к рантайму.

special-k ★★★★
() автор топика

1000 строк. Т.е тебе нужно всего сделать 1000 запросов? Зачем тут оптимизации? Или тебе постоянно такие вещи нужно делать?

pi11 ★★★★★
()

Можешь попробовать select str from tbl where str in (?, ..., ?), но совет про временную таблицу скорее всего будет оптимальней.

Legioner ★★★★★
()

Если ты делаешь такие операции часто, то сделай еще одну таблицу c двумя столбцами, если возможно укажи директиву чтобы была в памяти, если СУБД поддерживает. В первом идентификатор операции, уникальный какой-то номера, например UUID, во втором столбце твои строки. А потом уже какой-то JOIN. Данные легко вводить - batch. Легко потом почистить таблицу после операции - удалить все с текущим UUID

vertexua ★★★★★
()
Последнее исправление: vertexua (всего исправлений: 2)
Ответ на: комментарий от pi11

Да, это будет типичный запрос.

Ну.. 1000 запросов я в любом случае не планировал. Планировал как-то иначе, более эстетично.

special-k ★★★★
() автор топика

Дополнение: в исходном массиве ~100..1000 строк. В базе ~100k..1kk

Как вариант, хранить со строками хэши и сравнивать но ним. Но вообще не понятно, почему нельзя просто сделать выборку по имеющимся строкам.

no-such-file ★★★★★
()
Ответ на: комментарий от Legioner

select str from tbl where str in (?, ..., ?)

Кстати было у нас на одном проекте, что по безалаберности программиста был запрос с выборкой по in с огромным списком. Это привело к тому, что на оракле при превышении размера списка в около 1000 элементов оракл отказывался его обрабатывать. Там у них даже отдельная ORA ошибка на эту тему есть. Это чисто FYI для ТС если он решит воспользоваться этим вариантом.

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

с выборкой по in с огромным списком

А что, кстати происходит, если попадутся несуществующие значения, ничего, или ошибка?

special-k ★★★★
() автор топика
Ответ на: комментарий от special-k

Странный вопрос. Список в in вполне может содержать значения, которых нет в БД. В этом случае итоговая выборка полностью совпадает с той, которая возвращается запросом без этих значений в списке in.

Hater ★★
()
Ответ на: комментарий от special-k

Зависит от многих аспектов, очевидно :) Правильный вопрос: насколько оно быстрее/медленнее других подходов.

Так, например, это будет быстрее, чем выполнять отдельно запрос для каждого значения. Про вариант с временной таблицей - не знаю, умозрительно кажется что тоже быстрее, но я советую погонять тесты на семпловых данных.

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

Если честно, я не очень понял принцип подхода с временной таблицей.. Мне предлагают записать 1000 строк что ли?

Я попробовал в рантайме, и там это порядка 2мс для 1к элемнтов массива входящих строк и 3кк строк в «БД» (руби). Требует ~600МБ ОЗУ, но 3кк и даже 1кк - это глубокая перспектива. А в других случаях какой примерно порядок величин..?

special-k ★★★★
() автор топика
Ответ на: комментарий от special-k

Если честно, я не очень понял принцип подхода с временной таблицей

По моему vertexua все понятно разъяснил. Создается временная таблица, в нее данные можно грузить как одиночным, там и множественным запросом, а можно подгрузить из файла (если файл на сервере СУБД), но нужно смотреть какие у СУБД для этого возможности. Потом просто джоинишь данные из БД и этой временной таблицы. Результат запроса - список строк, присутствующих в БД и во временной таблице. С джоинаим еще поиграться можно, чтобы, например, выводил все строки из временной таблицы + те строки, которые есть в БД.

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

в нее данные можно грузить как одиночным, там и множественным запросом

Но ведь это.. долго? Совершенно же неприемлемые величины по времени при указанных вначале темы параметрах.. (для типичного веб-запроса имеется ввиду).

special-k ★★★★
() автор топика
Последнее исправление: special-k (всего исправлений: 1)
Ответ на: комментарий от special-k

делай асинхронно закидывай данные на сервер, запускай вёркер(как это по русски называется?), по завершении работы уведомляй пользователя

Jaberwock ★★★
()
Ответ на: комментарий от special-k

От задачи зависит. Если тебе просто проверить 1000 строк, как указано в ТС, то вообще не понятно почему возник вопрос. Но если предполагается какой-либо рост (как в объемах, так и в логике), то нужно смотреть на альтернативы. Вот загрузка файла во временную таблицу БД - это такая альтернатива. Если данные проверять приходится часто, а грузить редко, то грузить их можно и точечными инсертами. Мы твою задачу не знаем, мы предлагаем варианты.

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

Мы твою задачу не знаем, мы предлагаем варианты.

Задача: делать это в рамках ответа на пользовательский http запрос.

(Web-development же)

special-k ★★★★
() автор топика
Последнее исправление: special-k (всего исправлений: 1)
Ответ на: комментарий от special-k

А кастаника спецов по всяким сфинксам и чему-то похожему. Возможно тебе подойдет вариант с поддержанием в актуальном состоянии части данных из БД, по которым нужно делать проверку, в специализированном решении для текстового поиска. Вот тут я точно ничего сказать не могу.

anonymous
()
Ответ на: комментарий от special-k

закинули данные, ушли со страницы, на другой странице получили уведомление что данные обработаны

Jaberwock ★★★
()
Последнее исправление: Jaberwock (всего исправлений: 1)
Ответ на: комментарий от special-k

в рамках ответа пользователь ставит задачу в очередь и получает сообщение об успехе или провале

Jaberwock ★★★
()
Ответ на: комментарий от special-k

Кстати, присоединяюсь к предложению сделать обработку асинхронной. Вот это реально тема для Web-development же.

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

Асинхронность это хорошо, но ты же не будешь ждать ответа неделю ^_^ Да и ресурсы надо расходовать не на обогрев помещений..

А чем вам не нравится рантайм? Запихнул миллион строчек в хэш (благо они небольшие), и проверяешь..

special-k ★★★★
() автор топика
Последнее исправление: special-k (всего исправлений: 2)
Ответ на: комментарий от special-k

Где это асинхронность равна недельному ожиданию? Формируешь задание, которое забирает свободный обработчик, исполняет его, возвращает ответ. Тут дело даже не в том, что это долго, а в том, что тебе придется менять протокол взаимодействия с пользователем. Зато получаешь масштабируемость.

Не нравится тем, что однажды такое решение может не сработать. Выше приводили пример, когда оракл отказывался обрабатывать такой запрос. Если строки изменятся, это может хорошенько сказаться на производительности. Ты это обнаружишь не сразу, а пользователи сразу, т.к. у них страница будет подвисать. В асинхронном варианте пользователь может даже не ощутить проседания производительности. Короче, лучше продумай где ты можешь допустить деградацию производительности и используй эту возможность, чтобы упростить реализацию.

anonymous
()

Выясни максимальную длину SQL запроса и максимальное количество значений для IN (...). Если размер массива строк для проверки превышает эти значения разбей на несколько запросов. Т.е. если например БД принимает максимум по 100 значений в IN (...) для 1,000 строк 10 запросов по любому быстрее (вероятно, в 100 раз быстрее) чем 1,000 запросов.

Много запросов к БД это очень медленно, я видел индусский код который выбирал по 100 items на страницу из таблицы и вместо JOIN'а добирал потом данные из другой таблицы в цикле. Всё подвисало на несколько секунд и это на тестовой машине где пользователей больше не было. После замены на 1 запрос загружалось моментально.

FutureBoy
()

Ещё не забудь добавить INDEX для column в котором содержатся строки.

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

Нет смысла использовать для временной таблицы InnoDB.

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

Ок, мы сделаем воркеры и балансировщик, теперь надо выяснить как именно будет работать воркер.

special-k ★★★★
() автор топика
Ответ на: комментарий от FutureBoy

чем 1,000 запросов

Да не собирался я делать 1000 запросов. Но, может, типичные реляционные СУБД слишком тяжелы для данной задачи? Например http://redis.io/commands/hmget

special-k ★★★★
() автор топика
Ответ на: комментарий от special-k

в нее данные можно грузить как одиночным, там и множественным запросом

Но ведь это.. долго?

дык каждую строку так или иначе надо засунуть для проверки в СУБД. Оптом дешевле. Потому временная таблица быстрее всего (или также). Если конечно памяти хватит, если не хватит, придётся делать несколько временных таблиц, всяко лучше, чем по одному.

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

принимает максимум по 100 значений в IN (...)

а можно пример из практики для этого случая? А то я что-то не пойму, где у вас IN для 100+ значений нужен?

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

Разве INSERT с последующим JOIN'ом может быть быстрее чем просто SELECT .. IN (...)? Думаю уже по количеству запросов к DB такой подход проигрывает.

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

IN страдает тем, что многие БД ставят жесткое ограничение по количеству элементов. Если INSERT в память. То INSERT в память и JOIN теоретически ничем не отличаются от IN. А в реальной реализации нужно тестировать. Один Поттеринг знает что они там понаписывали

vertexua ★★★★★
()
Ответ на: комментарий от FutureBoy

Какие оба запроса? INSERT может идти как BATCH. Но драйвер разделит его на несколько запросов если надо. А IN сработает или не сработает и все. Если бы элеметов было меньше, то может быть лучше было использовать IN, так как тогда у нас был бы один round-trip

vertexua ★★★★★
()

Короче, я использую redis hash с одинаковым ключом и значением, и HMGET (соответственно).

special-k ★★★★
() автор топика
Последнее исправление: special-k (всего исправлений: 1)
Ответ на: комментарий от vertexua

Автор же написал что в исходном массиве до 1,000 строк.Если каждая строка по 255 символов получаем 255 * 1,000 == 0.24M. Щас глянул у меня в gentoo по default'у в /etc/mysql/my.cnf max_allowed_packet_size = 1M. Если не планируется использоваться скрипт на shared говнохостинге от godaddy разумнее увеличить это значение. Но вообще конечно no sql solution будет эффективнее, что автор и сделал, совершенно правильно.

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