Модераторы: skyboy
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> MySQL меняет порядок условий в WHERE, Как обойти? 
:(
    Опции темы
1programmist
Дата 29.8.2011, 12:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 22.12.2009

Репутация: нет
Всего: нет



Добрый день,

Столкнулся с проблемой, что mysql меняет порядок условий в WHERE.

Есть база:
Код

CREATE TABLE IF NOT EXISTS `con` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `cid` int(11) NOT NULL,
  `cdate` date NOT NULL,
  `type` smallint(6) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_CID` (`cid`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=5 ;

INSERT INTO `con` (`id`, `cid`, `cdate`, `type`) VALUES
(2, 2, '2011-08-11', 1),
(3, 3, '2011-06-01', 2),
(4, 4, '2011-06-15', 2);

CREATE TABLE IF NOT EXISTS `hist` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `id_con` int(11) NOT NULL,
  `update` date NOT NULL,
  PRIMARY KEY (`id`),
  KEY `IDX_CON` (`id_con`)
) ENGINE=MyISAM  DEFAULT CHARSET=latin1 AUTO_INCREMENT=6 ;

INSERT INTO `hist` (`id`, `id_con`, `update`) VALUES
(1, 2, '2011-08-29'),
(2, 2, '2011-08-01'),
(3, 2, '2011-07-20'),
(4, 3, '2011-06-08'),
(5, 4, '2011-06-23');


Выполняем запрос:
Код

explain SELECT
    c.cdate,
    c.type,
    h.id_con,
    max(h.update)    AS `update`,
    date_ymd         AS max_update,
    n                AS `month`
FROM
    con c,
    hist h,
    (
        SELECT '2011-08-25' AS date_ymd, 0 AS n
        UNION SELECT '2011-07-31', 1
        UNION SELECT '2011-06-30', 2
    ) AS `month`
WHERE 
    c.cid = 2 AND
    h.id_con = c.id AND
    `update`<= date_ymd
GROUP BY 
    id_con, date_ymd;



Видим следующее
user posted image

Uploaded with ImageShack.us

Т.е. всё по индексам проходит, всё ОК. Выполняем запрос и смотрим как mysql его преобразовывает
Код

explain extended SELECT
    c.cdate,
    c.type,
    h.id_con,
    max(h.update)    AS `update`,
    date_ymd         AS max_update,
    n                AS `month`
FROM
    con c,
    hist h,
    (
        SELECT '2011-08-25' AS date_ymd, 0 AS n
        UNION SELECT '2011-07-31', 1
        UNION SELECT '2011-06-30', 2
    ) AS `month`
WHERE 
    c.cid = 2 AND
    h.id_con = c.id AND
    `update`<= date_ymd
GROUP BY 
    id_con, date_ymd;



MySQL отдает, и собственно пытается выполнить, вот такой запрос:
Код
select 
    `test`.`c`.`cdate` AS `cdate`,
    `test`.`c`.`type` AS `type`,
    `test`.`h`.`id_con` AS `id_con`,
    max(`test`.`h`.`update`) AS `update`,
    `month`.`date_ymd` AS `max_update`,
    `month`.`n` AS `month` 
from 
    `test`.`con` `c` 
join 
    `test`.`hist` `h` 
join (
    select '2011-08-25' AS `date_ymd`,0 AS `n` 
    union select '2011-07-31' AS `2011-07-31`,1 AS `1` 
    union select '2011-06-30' AS `2011-06-30`,2 AS `2`
) `month` 
where (
    (`test`.`c`.`id` = `test`.`h`.`id_con`) and 
    (`test`.`c`.`cid` = 2) and 
    (`test`.`h`.`update` <= `month`.`date_ymd`)
) 
group by 
`test`.`h`.`id_con`,`month`.`date_ymd`



Как видим MySQL поменял очередность условий в WHERE (1 и 2 условие), что не очень хорошо сказывается на больших объемах данных. 
Пробовал в запросе в WHERE брать условия в скобки () чтобы указать очередность, но толку нет, всё равно MySQL именно так преобразовывает. Что делать?
PM MAIL WWW   Вверх
Akina
Дата 29.8.2011, 15:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 106
Всего: 454



Цитата(1programmist @  29.8.2011,  13:36 Найти цитируемый пост)
Как видим MySQL поменял очередность условий в WHERE (1 и 2 условие),

Он поступает совершенно логично.

Цитата(1programmist @  29.8.2011,  13:36 Найти цитируемый пост)
Что делать?

Ну разве что убрать условие c.cid = 2 в подзапрос... что мне кажется малосмысленным... или создать индекс con(cid, id) и попробовать его зафорсить.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
1programmist
Дата 29.8.2011, 15:57 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 22.12.2009

Репутация: нет
Всего: нет



Цитата(Akina @ 29.8.2011,  15:53)
Цитата(1programmist @  29.8.2011,  13:36 Найти цитируемый пост)
Как видим MySQL поменял очередность условий в WHERE (1 и 2 условие),

Он поступает совершенно логично.

Что-то логики я никакой не вижу, в таблице "с" 60млн записей, в таблице "h" около миллиарда. Что лучше, сначала связать таблицы и потом выбрать из них 20 записей или же наоборот?
PM MAIL WWW   Вверх
Akina
Дата 29.8.2011, 19:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 106
Всего: 454



Цитата(1programmist @  29.8.2011,  16:57 Найти цитируемый пост)
в таблице "с" 60млн записей, в таблице "h" около миллиарда. Что лучше, сначала связать таблицы и потом выбрать из них 20 записей или же наоборот? 

Это ты знаешь селективность построенных тобой условий. И то потому, что уже получал результаты этого запроса. А сервер этой селективности не знает, посему поступает так, как В БОЛЬШИНСТВЕ СЛУЧАЕВ будет оптимально.
Поскольку твои условия делают запрос "несреднестатистическим" - будь любезен подсказать серверу, как делать В ДАННОМ КОНКРЕТНОМ СЛУЧАЕ.
Как - я уже предложил пару вариантов.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
1programmist
Дата 30.8.2011, 07:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 22.12.2009

Репутация: нет
Всего: нет



Цитата(Akina @ 29.8.2011,  19:42)
Поскольку твои условия делают запрос "несреднестатистическим" - будь любезен подсказать серверу, как делать В ДАННОМ КОНКРЕТНОМ СЛУЧАЕ.
Как - я уже предложил пару вариантов.

Не помогло
user posted image[/url]
PM MAIL WWW   Вверх
Akina
Дата 30.8.2011, 11:41 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 106
Всего: 454



Цитата(1programmist @  30.8.2011,  08:37 Найти цитируемый пост)
Не помогло

А ты ничего и не сделал.
И эта... текстовые цитаты с консоли лучше мелкоскопных скриншотов.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
1programmist
Дата 30.8.2011, 12:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 22.12.2009

Репутация: нет
Всего: нет



Цитата(Akina @ 30.8.2011,  11:41)
Цитата(1programmist @  30.8.2011,  08:37 Найти цитируемый пост)
Не помогло

А ты ничего и не сделал.
И эта... текстовые цитаты с консоли лучше мелкоскопных скриншотов.

ну вообще-то вынес условие выше. Но опять же, я не прошу написать мне запрос, я прошу направить меня по правильному пути, чтобы решить проблему
PM MAIL WWW   Вверх
Akina
Дата 30.8.2011, 12:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 106
Всего: 454



Цитата(Akina @  29.8.2011,  16:53 Найти цитируемый пост)
убрать условие c.cid = 2 в подзапрос

Код

select 
    `test`.`c`.`cdate` AS `cdate`,
    `test`.`c`.`type` AS `type`,
    `test`.`h`.`id_con` AS `id_con`,
    max(`test`.`h`.`update`) AS `update`,
    `month`.`date_ymd` AS `max_update`,
    `month`.`n` AS `month` 
from 
    (
        select `cc`.*
        from `test`.`con` `cc`
        where `cc`.`cid` = 2
    ) `c` 
join 
    `test`.`hist` `h` 
join 
    (
        select '2011-08-25' AS `date_ymd`, 0 AS `n` 
    union 
        select '2011-07-31', 1 
    union 
        select '2011-06-30', 2
    ) `month` 
where (
    (`test`.`c`.`id` = `test`.`h`.`id_con`) and 
    (`test`.`h`.`update` <= `month`.`date_ymd`)
) 
group by 
`test`.`h`.`id_con`,`month`.`date_ymd`



Цитата(Akina @  29.8.2011,  16:53 Найти цитируемый пост)
или создать индекс con(cid, id) и попробовать его зафорсить

с этим сам справишься?


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | MySQL | Следующая тема »


 




[ Время генерации скрипта: 0.0540 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.