SQLinfo.ru - Все о MySQL Webew.ru: теория и практика веб-технологий

Форум пользователей MySQL

Задавайте вопросы, мы ответим

Вы не зашли.

#1 20.06.2013 01:27:49

Meshok
Участник
Зарегистрирован: 20.06.2013
Сообщений: 5

Запрос выборки

Помогите с, возможно, простым запросом.
Есть таблица получателей Email-рассылки


CREATE TABLE IF NOT EXISTS `ER` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_emailing` int(10) unsigned NOT NULL, -- ИД рассылки
  `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, -- email пользователя
  `status` varchar(10) COLLATE utf8_unicode_ci NOT NULL, -- статус отправки
  `error` varchar(255) COLLATE utf8_unicode_ci NOT NULL, -- описание ошибки
  `smtp_code` varchar(10) COLLATE utf8_unicode_ci NOT NULL, -- сод ошибки
  PRIMARY KEY (`id`),
  UNIQUE KEY `id_emailing` (`id_emailing`,`email`),
  KEY `id_emailing_2` (`id_emailing`,`status`)
) ENGINE=MyISAM  DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
 

Она заполняется email'ами перед каждой отправкой рассылки со статусом wait после отправки письма пользователю статус меняется на error или success.

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

Т.е. мне нужно узнать, что пользователь которому отправилось N рассылок все эти N рассылок получил со статусом error, точнее не получил.

Например email'у example@domain.com было отправлено 10 рассылок и все 10 он так и не получил,
а емейлу example2@domain.com было отправлено 3 рассылки, из которых он 3 не получил и т.д.

Также было бы интересно, как можно узнать какой процент из всех отправок был отправлен с ошибкой.

Неактивен

 

#2 20.06.2013 09:47:29

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: Запрос выборки

select email, sum(if(`status`='success',1,0)) c from er group by 1 having c=0; -- выбрать всех пользователей, у которых все рассылки были отправлены с ошибкой.


(select count(*) from er where `stutus` = 'error')*100/(select count(*) from er); -- какой процент из всех отправок был отправлен с ошибкой.

Неактивен

 

#3 20.06.2013 13:32:01

Meshok
Участник
Зарегистрирован: 20.06.2013
Сообщений: 5

Re: Запрос выборки

Спасибо! Работает.

Только в моей таблице на 800 000 записей запросы выполняется около 15 сек.
Можно его как-то оптимизировать, ускорить?
Поможет ли индекс на поле status, если есть общий индекс на поля id_emailing и status?
Есть ли еще какие-то варианты?

Еще вопрос. А что дает

group by 1
? Это только для работы SUM?

Отредактированно Meshok (20.06.2013 13:33:31)

Неактивен

 

#4 20.06.2013 14:01:40

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: Запрос выборки

Meshok написал:

Можно его как-то оптимизировать, ускорить?

попробуйте для первого запроса индекс на `email`, а для второго на `status`

Meshok написал:

Поможет ли индекс на поле status, если есть общий индекс на поля id_emailing и status?

FAQ №5

Meshok написал:

Есть ли еще какие-то варианты?

можно попробовать переписать первый запрос в виде
select er.email from er left join
(select email from er where `status`='success' group by 1) using(email) where t.email is null;

или

select email from er group by 1 having max(status)='error'; -- если вы уверены, что после рассылки не могут остаться записи со статус wait, то данный вариант оптимален при наличии индекса на (email,status). Правильно работать будет после осуществления рассылки, когда нет статуса wait (или можно изменить значение статуса с success на z_success.)

Meshok написал:

Еще вопрос. А что дает

group by 1
?

Это аналог group by `email`, чтобы меньше писать.

Неактивен

 

#5 20.06.2013 18:21:07

Meshok
Участник
Зарегистрирован: 20.06.2013
Сообщений: 5

Re: Запрос выборки

Теперь проблема, если я использую

select email from er group by 1 having max(status)='error'
, то все отлично работает и используются индекты и запрос быстро выполняется, а если я делаю так
select * from er group by email having max(status)='error'
, то индексы перестают использоваться.
А вообще мне нужно еще и JOIN'ы в этот запрос добавлять.

Индаксы создал для (email), (status) и (email, status) в первом случае используется (email, status).

Отредактированно Meshok (20.06.2013 18:21:32)

Неактивен

 

#6 20.06.2013 18:59:49

vasya
Архат
MySQL Authorized Developer
Откуда: Орел
Зарегистрирован: 07.03.2007
Сообщений: 5842

Re: Запрос выборки

Meshok написал:

Теперь проблема, если я использую

select email from er group by 1 having max(status)='error'
, то все отлично работает и используются индекты и запрос быстро выполняется, а если я делаю так
select * from er group by email having max(status)='error'
, то индексы перестают использоваться

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

Зачем вы выбираете все поля таблицы?

Meshok написал:

А вообще мне нужно еще и JOIN'ы в этот запрос добавлять.

Зачем? Этот запрос дает вам список email тех пользователей, у которых все рассылки были отправлены с ошибкой.

Meshok написал:

Индаксы создал для (email), (status) и (email, status) в первом случае используется (email, status).

При наличии (email, status) индекс на (email) лишний.

Неактивен

 

#7 20.06.2013 19:06:50

Meshok
Участник
Зарегистрирован: 20.06.2013
Сообщений: 5

Re: Запрос выборки

Мне нужно создать таблицу статистики с емейлами, именем, аватаркой пользователя, которому принадлежит емейл. Это минимум, что нужно. Остальное не критично, хотя еще есть такие потребности, как знать как был подписан пользователь (с помощью регисрации на сайте или через форму подписки) и т.п.

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

Неактивен

 

Board footer

Работает на PunBB
© Copyright 2002–2008 Rickard Andersson