MYSQL: обновление таблицы в последующие даты - PullRequest
1 голос
/ 11 марта 2012

Добрый вечер всем,

Я боролся с этим весь день.

Я пытаюсь обновить столбец в моей таблице клиентов, который покажет число раз они были подписчиком.Эта таблица создается из большого дампа данных, который имеет отдельные строки для каждого клиента, и каждый месяц они были подписчиками (для каждого месяца назначалось итеративное число).Имена уникальны.Это выглядит примерно так и показывает, что (например) Джейн Доу была подписчиком в период 1000, но не в период 1002.

Row_ID Customer_Name  Date_Code 
1      Jane Doe       1000      
2      Jane Doe       1001      
3      Jane Doe       1004      
4      Jane Doe       1005      
5      Ted Jones      1000      
6      Ted Jones      1001      
7      Ted Jones      1002      
etc...

В этом случае Джейн Доу была подписчиком 1000-1001, слеванаша подписка, а затем вернулся с 1004-1005.У меня есть основная таблица, которая включает в себя всю логику даты (дата начала, дата окончания, код даты и т. Д.).Это выглядит примерно так:

Start_Date   End_Date    Date_Code
1990-01-01   1990-03-31  1000
1990-04-01   1990-06-30  1001
1990-07-01   1990-09-30  1002
1990-10-01   1990-12-31  1003
etc...

Я пытаюсь найти способ сделать вывод примерно таким:

Customer_Name  Subscription_Count
Jane Doe       2
Ted Jones      1

Кто-нибудь сталкивался с чем-то подобным раньше?Для меня (как человека) очевидно, что числа являются (или нет) последовательными и (или не являются) представлением всего образца, но я не уверен, как заставить MYSQL это понять.Я ценю любые идеи.

* РЕДАКТИРОВАТЬ - я пробовал альтернативы «Присоединиться» и «Где не существует», и оба тайм-аута через 10 минут.Я полагаю, что это связано с размером основной таблицы (~ 100 000 строк).У вас есть какие-нибудь предложения?Еще раз спасибо за все комментарии.

** РЕДАКТИРОВАТЬ # 2 - После добавления индексов и небольшой настройки моих таблиц оба решения работают отлично.Еще раз спасибо за поддержку в выяснении этого.

Ответы [ 2 ]

1 голос
/ 11 марта 2012

Я не могу быть уверен на 100%, что это все еще так, но LEFT JOIN / IS NULL обычно быстрее, чем NOT EXISTS в MySQL -

SELECT t1.customer_name, COUNT(*) AS subscriptions
FROM   tbl t1
LEFT JOIN tbl t2
    ON t1.customer_name = t2.customer_name
    AND t1.date_code + 1 = t2.date_code
WHERE t2.customer_name IS NULL
GROUP BY t1.customer_name

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

CREATE UNIQUE INDEX `UQ_customer_date_code` ON tbl (customer_name, date_code);

Я провел несколько тестов, используя тестовую таблицу с 1,6 миллионами записей (100 000 клиентов в 21 коде даты).С этим индексом время запроса уменьшается примерно на 80%.Использование LEFT JOIN вместо NOT EXISTS только сокращает время запроса примерно на 15%.

1 голос
/ 11 марта 2012

Запрос может выглядеть примерно так:

SELECT customer_name, count(*) AS subscriptions
FROM   tbl AS t
WHERE NOT EXISTS (
    SELECT *
    FROM tbl AS t1
    WHERE t1.customer_name = t.customer_name
    AND t1.date_code = t.date_code + 1
    )
GROUP BY customer_name;

Хитрость заключается в том, чтобы исключить все строки, кроме одной на серию кодов даты_пользователя, а затем подсчитать: только последняя строка на блок не имеет преемника (date_code + 1).

Я предполагаю, что последовательные коды date_codes формируют одну подписку (согласно моему первому комментарию к вопросу). Следовательно, дополнительная информация о Start_Date и End_Date не требуется.


Производительность

LEFT JOIN / IS NULL на самом деле должен быть немного быстрее, чем NOT EXISTS в MySQL (как указано в @nnichols).
Гораздо важнее для производительности показатели. Чтобы это было быстро, вам нужны индексы на customer_name и date_code. Как это:

CREATE INDEX tbl_customer_name ON tbl(customer_name);
CREATE INDEX tbl_date_code ON tbl(date_code);
...