2013-08-31 2 views
0

Я добавил рекламные объявления на свой веб-сайт, у которых есть достаточно условий для встречи перед тем, как доставить пользователю просмотра. Вот подробное описание:Оптимизировать часто выполняемый запрос

Эти поля, которые требуют поясняющие:

start по умолчанию «0000-00-00», и это указывает, является ли объявление было еще уплаченной или нет. Когда платеж по объявлению принимается, start устанавливается на следующий день или в любую дату, когда клиент выбирает.

impresssions составляет соответственно остальные впечатления от рекламы

impressions_total и impressions_perday самообъясняющие

и другие поля, используемые в запросе лишь поля, VALIDATE попадает ли пользователь в спецификации реклама-х слуховой аппарат

Объявление должно быть оплачено, чтобы начать показ в первую очередь, однако его можно установить для начала в будущем, поэтому значение start будет установлено, но объявление не должны появляться до того, как пришло время. Тогда, поскольку клиенты могут ограничить количество показов в день, мне нужно подобрать только рекламные объявления с достаточным количеством показов на текущий день. Например, если реклама запущена в 30/08/2013 с 10 000 показов и 2000 показов в день, то она не должна появляться сегодня (31/08/2013), если она имеет менее 6000 показов, потому что это вторая день кампании. Кроме того, если срок действия периода составляет 5 дней и 5 дней, реклама должна быть показана независимо от оставшихся показов. Тогда есть и те другие сравнения, которые подтверждают, что пользователь подходит для показа этого объявления, и все это становится настолько сложным.

Я не очень хорошо разбираюсь в mysql, хотя мне удалось создать рабочий запрос, и я очень обеспокоен его оптимизацией. Я почти уверен, что методы, которые я использовал, очень неэффективны, но я не мог найти лучший способ в Интернете. Вот почему я задаю этот вопрос здесь, может ли кто-нибудь помочь мне улучшить производительность этого запроса?

SELECT `fields`, 
FROM `ads` 
WHERE (`impressions`>0 && `start`!='0000-00-00') 
AND `start`<CURDATE() AND 
    (
     `impressions`>(`impressions_total`-(CONVERT(CURDATE()-date(`start`), UNSIGNED)*`impressions_perday`)) 
     OR (`impressions_total`/`impressions_perday` < CURDATE()-date(`start`)) 

     -- this is the part where I validate the impressions for the day 
     -- and am most concerned that I haven't built correctly 
    ) 
AND 
(
    (
     (YEAR(NOW())-YEAR("user's birthday") BETWEEN `ageMIN` AND `ageMax`) 
     AND (`sex`=2 OR `sex`="user's gender") 
     AND (`country`='' OR `country`="user's country") 
    ) OR `applyToUnregistered` = 1 
) 
ORDER BY $random_order -- Generate random order pattern 

Схема:

CREATE TABLE `ads` (  
    `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 
 `headline` varchar(25) NOT NULL, 
 `text` varchar(90) NOT NULL, 
 `url` varchar(50) NOT NULL, 
 `country` varchar(2) DEFAULT '0', 
 `ageMIN` tinyint(2) unsigned NOT NULL, 
 `ageMax` tinyint(2) unsigned NOT NULL, 
 `sex` tinyint(1) unsigned NOT NULL DEFAULT '2', 
 `applyToUnregistered` tinyint(1) unsigned NOT NULL DEFAULT '0', 
 `creator` int(10) unsigned NOT NULL, 
 `created` int(10) unsigned NOT NULL, 
 `start` date NOT NULL, 
 `impressions_total` int(10) unsigned NOT NULL, 
 `impressions_perday` mediumint(8) unsigned NOT NULL, 
 `impressions` int(10) unsigned NOT NULL, 
 PRIMARY KEY (`id`) 
) ENGINE=MyISAM AUTO_INCREMENT=27 DEFAULT CHARSET=utf8 
+2

** Не указывайте/не возвращайте имена столбцов. ** Они добавляют только визуальный беспорядок и это еще один способ сделать синтаксические ошибки. Единственная причина, по которой вы нуждаетесь в них, - это то, что у вас есть имя столбца, которое является зарезервированным словом, и использование имен столбцов, которые являются зарезервированными словами, является ужасной идеей, так что это две вредные привычки, которые вы можете избежать сразу. –

+0

Оптимизация сложна без схемы. Пожалуйста, опубликуйте синтаксис create table. – zevra0

+0

@ zevra0 schema добавлено –

ответ

1

У вас есть очень сложный запрос с точки зрения оптимизации.

Единственные индексы, которые могут использоваться в договоре where, указаны на ads(impressions) или ads(start). Поскольку вы используете неравенства, вы не можете их комбинировать.

Можете ли вы изменить структуру таблицы, чтобы иметь ImpressionsFlag? Это будет 1, если есть какие-либо показы и 0 в противном случае. Если да, то вы можете попробовать индекс на ads(ImpressionsFlag, Start).

Если это поможет в производительности, следующим шагом будет разбиение запроса на отдельные подзапросы и объединение их с использованием union all. Целью является создание индексов для оптимизации базовых запросов.

+0

Почему я не могу добавить индекс в «показы», ​​поскольку он вместо добавления 'impressionsFlag'? –

+0

@php_nub_qq. , , Ты можешь. Однако индекс 'ads (Impressions, Start)', вероятно, не будет использоваться для двух условий, потому что первое является неравенством. Документация MySQL действительно хорошо объясняет это (http://dev.mysql.com/doc/refman/5.5/ru/mysql-indexes.html). –

+0

Итак, из всего, что вы сказали, мне не ясно, что такое «неравенство» и как я могу получить индекс на 2 столбца? Я имею в виду, как вы говорите «ads (Impressions, Start)»? –

Смежные вопросы