Задавайте вопросы, мы ответим
Вы не зашли.
Акутогава-сан, прошу простить мне слабоумие!
Неактивен
Вроде все логично. Во внешнем запросе сортировки нет, значит пользователю порядок не важен. Отсюда - сортировка в подзапросе лишняя.
Общее правило: если нет ORDER BY, то порядок не гарантирован, независимо от того откуда идет выборка.
Неактивен
Проверил на "5.5.22-log MySQL Community Server (GPL)" - он так себя не ведет, а зря.
Неактивен
У него так выглядит:
Неактивен
Раньше было иначе, и трава зеленее и деревья выше..
Проблема в том, что когда хочу пройти переменными по таблице в определенном порядке, то order by не поможет, так как where применяется до него. Раньше с этой целью можно было использовать вложенный подзапрос, а теперь нет
Причина в том, что раньше подзапросы в части from первым делом материализовались во временную таблицу, а теперь оптимизатор их оптимизирует. В MySQL 5.6 такое же поведение будет.
Неактивен
Можно ли сделать что-то, чтобы подзапрос не подходил по условиям на оптимизацию?
Неактивен
Поздравляю! Победа разума над машиной
Неактивен
Получается, что некоторые фишки с использованием переменных будут уже не очень-то и возможны?... Тот же легендарный топик про то, как выбирать по два и более элемента из группы путем пользовательских переменных - там решение забазировано в какой-то мере на то, что в подзапросе есть order by. Как поставлю MariaDB посвежее - проверю.
rgbeast, а есть уверенность, что оптимизатор не превратит
(select * from test_table WHERE user_id<10 UNION (SELECT * from test_table where user_id>=10)
в
(select * from test_table)?
Неактивен
deadka написал:
rgbeast, а есть уверенность, что оптимизатор не превратит
(select * from test_table WHERE user_id<10 UNION (SELECT * from test_table where user_id>=10)
в
(select * from test_table)?
Когда-нибудь может быть, но пока что он не проводит анализ математических (логических) утверждений. Есть риск, что один из запросов будет давать пустой результат и оптимизатор это поймет, но раз этот запрос срабатывает, значит пока он так не действует.
Может быть будет опция отключить оптимизацию для конкретного подзапроса или уже существует какой-нибудь более надежный способ навязать материализацию.
Неактивен
Да, подозрения подтверждаются
По следам http://sqlinfo.ru/forum/viewtopic.php?id=3839
mysql> create table t_3839(id int, login varchar(255),`time` int); Query OK, 0 rows affected (0.31 sec) mysql> insert into t_3839 values(1,'log1',10),(2,'log1',15),(3,'log2',100),(4,'log2',80),(5,'log3',11),(6,'log4',8); Query OK, 6 rows affected (0.01 sec) Records: 6 Duplicates: 0 Warnings: 0 mysql> set @i=0,@n=1,@l=''; select t.* from ( select * from t_3839 order by login, time desc) t where if (@l=login, @i:=@i+1,(@i:=0) or (@l:=login) or 1) and @i<@n; Query OK, 0 rows affected (0.02 sec) +------+-------+------+ | id | login | time | +------+-------+------+ | 2 | log1 | 15 | | 3 | log2 | 100 | | 5 | log3 | 11 | | 6 | log4 | 8 | +------+-------+------+ 4 rows in set (0.04 sec) mysql> select version(); +------------+ | version() | +------------+ | 5.1.52-log | +------------+ 1 row in set (0.02 sec)
На этой версии mysql отрабатывает как и раньше.
MariaDB [sqlinfo]> create table t_3839(id int, login varchar(255),`time` int); Query OK, 0 rows affected (0.23 sec) MariaDB [sqlinfo]> insert into t_3839 values(1,'log1',10),(2,'log1',15),(3,'log2 ',100),(4,'log2',80),(5,'log3',11),(6,'log4',8); Query OK, 6 rows affected (0.28 sec) Records: 6 Duplicates: 0 Warnings: 0 MariaDB [sqlinfo]> set @i=0,@n=1,@l=''; select t.* from ( select * from t_3839 order by login, time desc) t where if (@l=login, @i:=@i+1,(@i:=0) or (@l:=login) or 1) and @i<@n; Query OK, 0 rows affected (0.00 sec) +------+-------+------+ | id | login | time | +------+-------+------+ | 1 | log1 | 10 | +------+-------+------+ 1 row in set (0.00 sec) MariaDB [sqlinfo]> select version(); +--------------------+ | version() | +--------------------+ | 5.5.34-MariaDB-log | +--------------------+ 1 row in set (0.01 sec)
Не отработало, как ожидалось.
C выборкой элементов группы
MariaDB тоже выдал не ожидаемый результат:
MariaDB [sqlinfo]> set @n=3, @i=0, @p=0; select * from (select * from g t1 join p t2 on t1.x=t2.y order by t1.x) t WHERE if (@p=x, @i:=@i+1,(@i:=0) or (@p:=x)) and @i<@n; Query OK, 0 rows affected (0.02 sec) +------+------+------+ | x | y | data | +------+------+------+ | 3 | 3 | 172 | | 3 | 3 | 721 | | 3 | 3 | 652 | +------+------+------+ 3 rows in set (0.05 sec) MariaDB [sqlinfo]>
Неактивен
Можно инициализировать переменные внутри подзапроса. Например, если раньше при необходимости сделать одним запросом, я пару запросов
Неактивен
Есть такой трюк, да. Правда выполнению вышеприведенных запросов в mariaDB не способствует . Вот и еще один аргумент в сторону того, чтобы не использовать переменные таким вот образом..
Неактивен
Поклёп! Для данных из прошлого примера:
Неактивен
Не, не поклеп.
Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 30 Server version: 5.5.34-MariaDB-log mariadb.org binary distribution Copyright (c) 2000, 2013, Oracle, Monty Program Ab and others. Type 'help;' or '\h' for help. Type '\c' to clear the current input statement. MariaDB [(none)]> use sqlinfo; Database changed MariaDB [sqlinfo]> SELECT * FROM t_3839 t; +------+-------+------+ | id | login | time | +------+-------+------+ | 1 | log1 | 10 | | 2 | log1 | 15 | | 3 | log2 | 100 | | 4 | log2 | 80 | | 5 | log3 | 11 | | 6 | log4 | 8 | +------+-------+------+ 6 rows in set (0.00 sec) MariaDB [sqlinfo]> select t.* from ( select * from t_3839, (select @i:=0,@n:=1,@ l:='') x order by login, time desc) t where if (@l=login, @i:=@i+1,(@i:=0) or (@ l:=login) or 1) and @i<@n; +------+-------+------+-------+-------+--------+ | id | login | time | @i:=0 | @n:=1 | @l:='' | +------+-------+------+-------+-------+--------+ | 2 | log1 | 15 | 0 | 1 | | +------+-------+------+-------+-------+--------+ 1 row in set (0.02 sec) MariaDB [sqlinfo]> select version(); +--------------------+ | version() | +--------------------+ | 5.5.34-MariaDB-log | +--------------------+ 1 row in set (0.23 sec) MariaDB [sqlinfo]>
А у тебя какая версия mariaDB?
Неактивен
5.3.5-MariaDB-log
Но в ней уже есть оптимизация from подзапросов. Видимо ещё что-то сменили.
Неактивен
С другой стороны, ничего удивительного. Дока не гарантирует корректную работу, если определять переменную в внутри тог же запроса где и происходят вычисления.
Т.е. раньше просто везло.
Неактивен
А покажите как в MySQL 5.1 или 5.5 выглядит
Неактивен
5.5.22-log MySQL Community Server (GPL):
Неактивен
Тогда ещё один вопрос - а сам запрос правильно отрабатывает?
Неактивен
Вот результат:
Неактивен
Ага, так я и думал. Похоже дело в
(<cache>((@i:=0)) or (@l:=`t`.`login`) or 1))
т.е. оптимизатор догоняет, что это выражение всегда будет истина и не вычисляет его в дальнейшем, т.е. не сбрасывает счетчик.
Но вот вопрос, если мы поле login определим как int, то уже нельзя будет заранее сказать, что выражение всегда будет истина, однако и в этом случае будет
(<cache>((@i:=0)) or (@l:=`t`.`login`)))
Имхо, это бага.
Неактивен
Если бага оптимизатора, то сделай пример, неправильность отработки которого очевидна и на bugs.mysql.com
Неактивен
Неактивен
Кстати, логично, что запрос работает в MariaDB 5.3 и неправильно работает в MariaDB 5.5 и MySQL 5.5, так как условно можно сказать, что
MariaDB 5.5 = MariaDB 5.3 + MySQL 5.5
(т.е. в версию 5.3 импортировали улучшения из MySQL 5.5 отсюда и такое распределение ошибки).
Неактивен
vasya, пример пока не понял, но его наглядность привела к идее демотиватора
Неактивен