2015-12-23 1 views
0

Скажите, что у вас есть таблица с миллионами записей - назовем каждый из них «item». В таблице есть несколько столбцов, включая один булевский столбец - назовем его isProcessed - и один с адресом электронной почты рабочего, который обрабатывал элемент - назовем его worker.Как эффективно получать данные и подсчитывать строки за один качели?

Допустим, работник Джон Смит ([email protected]) вызывает событие, которое должно вернуть (1) все необработанные элементы (isProcessed = ложь), с одной стороны, и (2) числа предметы, обработанные Джоном с другой.

Моя первая идея состояла в том, чтобы просто выполнить два запроса, один из которых выбирает элементы, а второй - все элементы, обработанные Джоном.

Но это кажется довольно неэффективным, потому что мне нужно повторять два раза по всем миллионам записей. Я мог бы также перебирать каждую строку и одновременно проверять оба столбца isProcessed и worker, поэтому я не запускаю таблицу дважды.

Что касается производительности кода, какой подход более эффективен в SQL? Или, в общем, какой подход рекомендуется?

+0

Немного. Является ли «(1)» предметом, назначенным Джону, но еще не обработанным? Или это подсчет? Или это все необработанные предметы (и «Джон» не имеет отношения к «(1)».) Просьба уточнить. –

+0

@ RickJames, нет, «(1)» и «(2)» просто указывают в этом вопросе, что нужно сделать две вещи. Цифры не имеют никакого отношения к самой операции (ей). – jaySon

+0

Это все необработанные предметы для Джона? Или все необработанные предметы для всех. (Решение радикально отличается.) –

ответ

0

Вы можете сделать это в одном запросе:

select count(*) as NumProcessed, sum(isProcessed = 0) as NumUnprocessed 
from t 
where worker = '[email protected]'; 
+0

Я не думаю, что есть «необработанные» элементы от «john», так как «john» применяется только тогда, когда «john» обрабатывает его. –

+0

Ваше предположение верно. Нет необработанных элементов без адреса электронной почты. ** Но ** я не имел в виду количество необработанных элементов, но сами соответствующие строки. Поэтому вместо 'select count (*) ...', это должно быть 'select * ... where isProcessed = 0'. – jaySon

0

Я бы рекомендовал добавить пункт, например, как это:

SUM(IF(worker='john', 1, 0)) AS johncount 

Это позволит эффективно рассчитывать количество раз «Джон» является worker в ряд.

0

Это зависит от индексов и от того, полезны они.

Обычно «флаги» (isProcessed) не полезны для индексации, поскольку их «мощность» не очень хороша. Вместо этого проще и (обычно) быстрее выполнять сканирование таблицы. Следовательно, INDEX(isProcessed), вероятно, будет бесполезным.

OTOH, worker='John' может быть полезным. Но нет, если Джон обрабатывает четверть предметов. Таким образом, сомнительно, было бы полезно использовать INDEX(worker).

Если оба индекса были полезны, то это было бы убыстрение:

(SELECT 'unprocessed' AS x, COUNT(*) AS ct FROM tbl WHERE isProcessed = false) 
UNION ALL 
(SELECT 'processed' AS x, COUNT(*) FROM tbl WHERE worker = 'John'); 
0

Вы могли бы рассмотреть возможность сохранения таблицы t подстановки с двумя колонками, worker и processed_count, подсчета количества обработанных деталей на одного работника. Эта таблица может храниться синхронно с помощью триггеров и будет содержать одну строку с worker = NULL (или некоторым магическим текстом), чтобы сохранить число необработанных элементов.

Тогда вы могли бы

SELECT processed_count FROM t AS unprocessed WHERE worker IS NULL

и

SELECT processed_count FROM t AS processed_by_john WHERE worker='john'

таблица будет расти линейно с числом рабочих и может быть индекс организован, если у вас есть много рабочих.