PDA

Просмотр полной версии : JOIN таблиц, как написать


DiffuSer
23.10.2010, 02:14
Как исключить из выдачи запроса SELECT * FROM `characters` персонажей на GM-аккаунтах?

tempura
23.10.2010, 03:05
без join-ов всяких...
SELECT * FROM `characters`.`characters` WHERE `account` NOT IN
(SELECT `id` FROM `realmd`.`account` WHERE `gmlevel` !=0);

DiffuSer
23.10.2010, 03:25
Благодарю.

Konctantin
23.10.2010, 10:45
а можно и с джойнами
SELECT c.*, a.*
FROM `characters`.`characters` c
LEFT JOIN `realmd`.`account` a
ON a.id = c.guid && a.gmlevel = 0;

virusav
23.10.2010, 13:53
LEFT JOIN тут не нужен вообще, обычный перекрестный запрос на выборку данных.

LordJZ
23.10.2010, 14:02
без join-ов всяких...
SELECT * FROM `characters`.`characters` WHERE `account` NOT IN
(SELECT `id` FROM `realmd`.`account` WHERE `gmlevel` !=0);И будет он для каждого ряда из characters выполнять запрос в realmd.account.а можно и с джойнами
SELECT c.*, a.*
FROM `characters`.`characters` c
LEFT JOIN `realmd`.`account` a
ON a.id = c.guid && a.gmlevel = 0;Если исправить ошибки в запросе, то он вернет всех персонажей, и для некоторых — их аккаунты.

Наиболее адекватный на мой взгляд запрос:SELECT c.* FROM characters.characters c, realmd.account a WHERE c.account = a.id AND a.gmlevel = 0 LIMIT X;Можете меня поправить.

Deamon
23.10.2010, 21:28
Наиболее адекватный на мой взгляд запрос:SELECT c.* FROM characters.characters c, realmd.account a WHERE c.account = a.id AND a.gmlevel = 0 LIMIT X;Можете меня поправить.

Такой запрос скорее всего сделает декартово произведеие таблиц characters и realmd, а только потом из полученного венегрета будет выбирать записи, удовлетворяющие условию where.

ИМХО, самым адекватным будет немного переделанный вариант того, что предложил Константин
SELECT c.*
FROM `realmd`.`account` a
LEFT JOIN `characters`.`characters` c ON c.account = a.id
where a.gmlevel = 0;
Набор данных в таблице account по определению меньше, чем набор данных из таблицы characters. Этот запрос сначала сделает выборку всех гмских акков из таблицы account, а затем left join'ом присоединит к ним персонажей из соответствующей таблицы.

Единственная неприятность, которая здесь есть - как из таблицы characters так и из таблицы account будут производится неиндексированные чтения, т.к. не задействуется ни primary key, ни secondary key(если они вообще есть). На малых массивах данных - это значения играть не будет. Но если скажем база персонажей разрастется до 1-го ляма - тогда начнут быть видны проблемы.

Lordronn
23.10.2010, 21:37
Какой запрос пройдет быстрее, обычный перекрестный, или тот, который предложил Константин?

LordJZ
23.10.2010, 21:41
Такой запрос скорее всего сделает декартово произведеие таблиц characters и realmd, а только потом из полученного венегрета будет выбирать записи, удовлетворяющие условию where.

ИМХО, самым адекватным будет немного переделанный вариант того, что предложил Константин
SELECT c.*
FROM `realmd`.`account` a
LEFT JOIN `characters`.`characters` c ON c.account = a.id
where a.gmlevel = 0;
Набор данных в таблице account по определению меньше, чем набор данных из таблицы characters. Этот запрос сначала сделает выборку всех гмских акков из таблицы account, а затем left join'ом присоединит к ним персонажей из соответствующей таблицы.

Единственная неприятность, которая здесь есть - как из таблицы characters так и из таблицы account будут производится неиндексированные чтения, т.к. не задействуется ни primary key, ни secondary key(если они вообще есть). На малых массивах данных - это значения играть не будет. Но если скажем база персонажей разрастется до 1-го ляма - тогда начнут быть видны проблемы.На 90 тыс. персонажей и 60 тыс. аккаунтов мой запрос работает в полтора раза быстрее вашего, и почти в 3 раза быстрее tempura-вского.

Добавлено: правда, у меня почти полностью закеширована account.Какой запрос пройдет быстрее, обычный перекрестный, или тот, который предложил Константин?Запрос от Konctantin некорректен, неужели выше я выразился настолько неясно?

virusav
23.10.2010, 21:43
Лорд, проверь этот запрос у себя на скорость.
SELECT
`characters`.*
FROM
`characters`.`characters`, `realmd`.`account`
WHERE
`characters`.`account`=`account`.`id`
AND `account`.`gmlevel`=0
ORDER BY
NULL;

LordJZ
23.10.2010, 21:45
Лорд, проверь этот запрос у себя на скорость.
SELECT
`characters`.*
FROM
`characters`.`characters`, `realmd`.`account`
WHERE
`characters`.`account`=`account`.`id`
AND `account`.`gmlevel`=0
ORDER BY
NULL;Практически тоже самое, что и у Deamon-а. 93 мс против 94 мс. (может сказалось кеширование)

virusav
23.10.2010, 21:57
Обязательно.
Первый раз выполняешь запрос, далее уже из кеша вызывается.

Мой запрос выбирал 1425 записей из таблицы персов и одну из аккаунтов.
Запрос Deamon - 1288 из таблицы персов и две из аккаунтов.

Ключи и количество записей можно смотреть командой EXPLAIN перед запросом.
ORDER BY NULL позволяет принудительно убрать сортировку при запросе на выборку, даже если сам запрос не содержит ORDER BY.
Очень помогает при выборе большого количества данных, когда сортировка не имеет значения.
EXPLAIN позволяет видеть, когда в запрос добавляется сортировка.

LordJZ
23.10.2010, 23:28
characters не кешируется, это же живой сервер.

DiffuSer
23.10.2010, 23:32
Всё, спасибо, разобрался. :)