Ru-MaNGOS

Ru-MaNGOS (http://mangos.ytdb.ru/index.php)
-   Флудильня (http://mangos.ytdb.ru/forumdisplay.php?f=30)
-   -   JOIN таблиц, как написать (http://mangos.ytdb.ru/showthread.php?t=2731)

DiffuSer 23.10.2010 02:14

JOIN таблиц, как написать
 
Как исключить из выдачи запроса 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

Цитата:

Сообщение от tempura (Сообщение 15294)
без join-ов всяких...
Код:

SELECT * FROM `characters`.`characters` WHERE `account` NOT IN
(SELECT `id` FROM `realmd`.`account` WHERE `gmlevel` !=0);


И будет он для каждого ряда из characters выполнять запрос в realmd.account.
Цитата:

Сообщение от Konctantin (Сообщение 15300)
а можно и с джойнами
Код:

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

Цитата:

Сообщение от LordJZ (Сообщение 15321)
Наиболее адекватный на мой взгляд запрос:
Код:

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

Цитата:

Сообщение от Deamon (Сообщение 15324)
Такой запрос скорее всего сделает декартово произведеие таблиц 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.
Цитата:

Сообщение от Lordronn (Сообщение 15325)
Какой запрос пройдет быстрее, обычный перекрестный, или тот, который предложил Константин?

Запрос от 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

Цитата:

Сообщение от virusav (Сообщение 15327)
Лорд, проверь этот запрос у себя на скорость.
Код:

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

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


Текущее время: 19:50. Часовой пояс GMT +3.

ru-mangos.ru - Русское сообщество MaNGOS