Mysql Можно ли как-нибудь оптимизировать 5+ join-ов + group+вложенный запрос? Выполнение - 20 секунд

VVWind

Новичок
У меня есть запрос и он еще расширяется в скрипте. Сам запрос выполняется в течение 20 секунд при 1 000 000+ записях в таблице.

PHP:
SELECT  client_1.*, GROUP_CONCAT(distinct tags.value SEPARATOR ', ') as tags, GROUP_CONCAT(distinct phone_1.phone SEPARATOR ', ') as phone,
GROUP_CONCAT(distinct email_1.email SEPARATOR ', ') as email
              FROM client_1
              LEFT JOIN phone_1
              ON phone_1.cid = client_1.cid
	      LEFT JOIN email_1
              ON email_1.cid = client_1.cid
              LEFT JOIN tags
              ON tags.tid in (select distinct tid from client_tag_1 where cid=client_1.cid)
              WHERE client_1.deleted='0000-00-00 00:00:00' or client_1.deleted=''
              GROUP BY client_1.cid limit 0, 1000
С одной стороны, можно выполнить это в php скрипте, но вы понимаете, сколько там будет циклов, плюс количество left join может быть расширено вообще до 10+ с различными названиями таблиц (типа address_1 или field_365).
Суть естественно проста, мне просто нужно собрать массив со всеми данными всех полей основываясь на cid.
То есть, если делать в скрипте, к примеру вместо left join в одном запросе делать 10+ запросов mysql_query с селектами а после с mysql_fetch_array доставать айди и выбирать снова в других таблицах все, получится огромнейшее количество циклов с перебором массивов, чтобы каждый элемент полного массива с данными имел совпадающую по айди информацию.

К примеру, представим если выбрали в client_1 5 записей, там cid = (1,2,3,4,5)
После с помощью IN выбрали в phone_1. А там оказалось 15 записей, так как телефонов по несколько на одного клиента. То есть теперь надо делать цикл с перебором, чтобы присоединять правильно к клиенту телефоны. Представьте, что будет с 1000 записями.

Есть ли возможно оптимизировать этот запрос, не переходя на вариант решения задачи в скрипте?
 

Gas

может по одной?
индексы phone_1.cid, email_1.cid, client_tag_1.cid, tags.tid есть ?
попробуй tags.tid in (select distinct tid from client_tag_1 where cid=client_1.cid) заменить на джоин вместо подзапроса

ну и explain показывай
 

VVWind

Новичок
PHP:
id   select_type 	table 	type 	possible_keys 	key 	key_len 	ref 	rows 	Extra
1 	PRIMARY 	client_1 	ALL 	NULL	NULL	NULL	NULL	1967583 	Using where; Using temporary; Using filesort
1 	PRIMARY 	phone_1 	ref 	cid 	cid 	4 	clients.client_1.cid 	1 	Using index
1 	PRIMARY 	email_1 	ref 	cid 	cid 	4 	clients.client_1.cid 	1 	Using index
1 	PRIMARY 	tags 	ALL 	NULL	NULL	NULL	NULL	216 	
2 	DEPENDENT SUBQUERY 	client_tag_1 	unique_subquery 	tid,tid_2,cid 	tid 	8 	func,clients.client_1.cid 	1 	Using index; Using where
 

Gas

может по одной?
на tags.tid похоже нет индекса

кстати, у тебя стоит limit 0, 1000, а всё это действо происходит над таблицей в ~2M, причём даже сортировки нет

если нужно 1000 записей, то сначала вложенным запросом достань 1000, а потом уже джойнь к ним остальные таблицы

PHP:
SELECT  t.*, 
        GROUP_CONCAT(distinct tags.value SEPARATOR ', ') as tags, 
        GROUP_CONCAT(distinct phone_1.phone SEPARATOR ', ') as phone,
        GROUP_CONCAT(distinct email_1.email SEPARATOR ', ') as email
FROM
(
  SELECT * FROM client_1 WHERE deleted='0000-00-00 00:00:00' or deleted='' LIMIT 0, 1000
) AS t
LEFT JOIN phone_1 ON phone_1.cid = t.cid
LEFT JOIN email_1 ON email_1.cid = t.cid
LEFT JOIN tags ON tags.tid in (select distinct tid from client_tag_1 where cid=t.cid)
GROUP BY t.cid
и что касается подзапроса с тегами, попробуй так написать

PHP:
SELECT  t.*, 
        GROUP_CONCAT(distinct tags.value SEPARATOR ', ') as tags, 
        GROUP_CONCAT(distinct phone_1.phone SEPARATOR ', ') as phone,
        GROUP_CONCAT(distinct email_1.email SEPARATOR ', ') as email
FROM
(
  SELECT * FROM client_1 WHERE deleted='0000-00-00 00:00:00' or deleted='' LIMIT 0, 1000
) AS t
LEFT JOIN phone_1 ON phone_1.cid = t.cid
LEFT JOIN email_1 ON email_1.cid = t.cid
LEFT JOIN client_tag_1 ON client_tag_1.cid=t.cid
LEFT JOIN tags ON tags.tid = client_tag_1.tid
GROUP BY t.cid
 

VVWind

Новичок
Gas, я если честно в шоке. Я не думал, что время выполнения запроса можно сократить до 0,7 секунд. Большое вам спасибо, очень помогли!
Могу ли я вас попросить посоветовать по вашему мнению лучшую книгу по sql?
 

VVWind

Новичок
Большое спасибо!
Первый и второй запрос имеют примерно одинаковую скорость. Первый раз первый за 1 секунду второй за 0,7
Но вот второй раз оба запроса показывают то 0,0001 то 0,0002
 
Сверху