|  | 
Задавайте вопросы, мы ответим
Вы не зашли.
SELECT
    c.id card,
    b.name b_name,
    b.document_url b_url,
    ug.id_package,
    o.id,
    o.title,
    o.description,
    o.telephone,
    o.publish_site,
    o.date_create,
    o.city adress,
    s.domain site
FROM links l
    JOIN `usage` u ON l.`id_usage` = u.`id`
    JOIN `organizations` o ON l.`id_organization` = o.id
    JOIN `cards` c ON o.id = c.`id_organization`
    JOIN `usage_groups` ug ON o.id = ug.`id_organization`
    JOIN `businesses` b ON b.id = l.id_business
    JOIN `sites` s ON o.id = s.id_organization
    LEFT JOIN `businesses` b1 ON l.`id_business` = b1.`id`
    LEFT JOIN `businesses` b2 ON b2.`id` = b1.`id_parent`
    LEFT JOIN `businesses` b3 ON b3.`id` = b2.`id_parent`
    LEFT JOIN `businesses` b4 ON b4.`id` = b3.`id_parent`
WHERE o.publish = 'Y'
     AND 189 IN (
                l.`id_business`,
                b1.`id_parent`,
                b2.`id_parent`,
                b3.`id_parent`,
                b4.`id_parent`
                )             
GROUP BY ug.`id_organization`
ORDER BY ug.id_package DESC, o.date_create
LIMIT 100, 10
CREATE TABLE `organizations` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_creator` int(10) unsigned DEFAULT NULL,
  `id_region` int(10) unsigned DEFAULT NULL,
  `id_business` int(10) unsigned DEFAULT NULL,
  `title` varchar(255) NOT NULL DEFAULT '',
  `inn` varchar(20) DEFAULT NULL,
  `kpp` varchar(20) DEFAULT NULL,
  `bank` varchar(255) DEFAULT NULL,
  `bank_bik` varchar(20) DEFAULT NULL,
  `bank_c_account` varchar(20) DEFAULT NULL,
  `bank_account` varchar(20) DEFAULT NULL,
  `date_create` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `date_disable` datetime DEFAULT NULL,
  `disable_reason` varchar(255) DEFAULT NULL,
  `description` text,
  `city` varchar(255) DEFAULT NULL,
  `publish` char(1) DEFAULT NULL,
  `publish_site` char(1) DEFAULT NULL,
  `logo` varchar(255) DEFAULT NULL,
  `telephone` varchar(60) DEFAULT NULL,
  `fax` varchar(20) DEFAULT NULL,
  `site` varchar(255) DEFAULT NULL,
  `email` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_organizations_region` (`id_region`),
  KEY `FK_organizations_business` (`id_business`),
  KEY `FK_organizations_creator` (`id_creator`),
  KEY `publish` (`publish`),
  KEY `date_create` (`date_create`),
  CONSTRAINT `FK_organizations_business` FOREIGN KEY (`id_business`) REFERENCES `businesses` (`id`),
  CONSTRAINT `FK_organizations_creator` FOREIGN KEY (`id_creator`) REFERENCES `users` (`id`),
  CONSTRAINT `FK_organizations_region` FOREIGN KEY (`id_region`) REFERENCES `regions` (`id`)
) ENGINE=InnoDB DEFAULT;
CREATE TABLE `usage_groups` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `id_package` int(10) unsigned NOT NULL DEFAULT '0',
  `id_organization` int(10) unsigned NOT NULL DEFAULT '0',
  `date_create` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `note` varchar(255) DEFAULT NULL,
  `card` varchar(45) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_usage_group_package` (`id_package`),
  KEY `FK_usage_group_organiuzation` (`id_organization`),
  KEY `id_package` (`id_package`,`id_organization`),
  CONSTRAINT `FK_usage_group_organization` FOREIGN KEY (`id_organization`) REFERENCES `organizations` (`id`),
  CONSTRAINT `FK_usage_group_package` FOREIGN KEY (`id_package`) REFERENCES `packages` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `cards` (
  `id` int(8) unsigned zerofill NOT NULL AUTO_INCREMENT,
  `id_series` int(10) unsigned NOT NULL DEFAULT '0',
  `id_organization` int(10) unsigned DEFAULT NULL,
  `id_package` int(10) unsigned NOT NULL DEFAULT '0',
  `date_pay` datetime DEFAULT NULL,
  `id_region` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_cards_series` (`id_series`),
  KEY `FK_cards_organization` (`id_organization`),
  KEY `FK_cards_package` (`id_package`),
  KEY `id_region` (`id_region`),
  CONSTRAINT `FK_cards_organization` FOREIGN KEY (`id_organization`) REFERENCES `organizations` (`id`),
  CONSTRAINT `FK_cards_package` FOREIGN KEY (`id_package`) REFERENCES `packages` (`id`),
  CONSTRAINT `FK_cards_series` FOREIGN KEY (`id_series`) REFERENCES `series` (`id`)
) ENGINE=InnoDB DEFAULT;
EXPLAIN:
id    select_type    table    type        key    key_len    ref    rows    Extra
1    SIMPLE    c    index        FK_cards_organization    5        105400    Using index; Using temporary; Using filesort
1    SIMPLE    o    eq_ref        PRIMARY    4    test.c.id_organization    1    Using where
1    SIMPLE    ug    ref        FK_usage_group_organiuzation    4    test.o.id    1    Using where
1    SIMPLE    l    ref        FK_links_organizations_id    4    test.c.id_organization    1    
1    SIMPLE    b1    eq_ref        PRIMARY    4    test.l.id_business    1    
1    SIMPLE    b2    eq_ref        PRIMARY    4    test.b1.id_parent    1    
1    SIMPLE    b3    eq_ref        PRIMARY    4    test.b2.id_parent    1    
1    SIMPLE    b4    eq_ref        PRIMARY    4    test.b3.id_parent    1    Using where
1    SIMPLE    s    ref        FK_sites_organization    5    test.o.id    1    Using where
1    SIMPLE    u    eq_ref        PRIMARY    4    test.l.id_usage    1    Using index
1    SIMPLE    b    eq_ref        PRIMARY    4    test.l.id_business    1    
Время выполнения 0.20 сек. Хочется избавиться от filesort и temporary.
Неактивен

Какая жуть 
1. Насколько я вижу, b1 тождественно равно b в этом запросе => -1 таблица.
2. Время выполнения не такое уж и плохое для такого запроса, Вы просто хотите
избавиться от страшных слов, или боитесь, что упретесь в производительность
на 10 миллионах карточек?
3. Боюсь, если Вы хотите сделать это быстрее - прийдется перепродумать структуру.
Кусок типа "189 in (...)" никогда не будет использовать индекс.
Неактивен
paulus написал:
Какая жуть
1. Насколько я вижу, b1 тождественно равно b в этом запросе => -1 таблица.
Убрал b1.
На скорость никак не повлияло, или малозаметно. Хотя она и правда лишняя.
paulus написал:
2. Время выполнения не такое уж и плохое для такого запроса, Вы просто хотите
избавиться от страшных слов, или боитесь, что упретесь в производительность
на 10 миллионах карточек?
Размер запроса  и страшные слова не волнуют - главное скорость!
paulus написал:
3. Боюсь, если Вы хотите сделать это быстрее - прийдется перепродумать структуру.
Кусок типа "189 in (...)" никогда не будет использовать индекс.
По-моему они все таки используются (обратите внимание на eq_ref):
id    select_type    table    type    possible_keys    key    key_len    ref    rows    Extra
1    SIMPLE    b    eq_ref    PRIMARY    PRIMARY    4    test.l.id_business    1    
1    SIMPLE    b2    eq_ref    PRIMARY    PRIMARY    4    test.b.id_parent    1    
1    SIMPLE    b3    eq_ref    PRIMARY    PRIMARY    4    test.b2.id_parent    1    
1    SIMPLE    b4    eq_ref    PRIMARY    PRIMARY    4    test.b3.id_parent    1    Using where
Перенес позиции таблиц в запросе - ug на 1е место, и создал индекс для с (id_organization, id)
SELECT
    c.id card,
    b.name b_name,
    b.document_url b_url,
    ug.id_package,
    o.id,
    o.title,
    o.description,
    o.telephone,
    o.publish_site,
    o.date_create,
    o.city adress,
    s.domain site
FROM `usage_groups` ug    
    JOIN `organizations` o ON ug.`id_organization` = o.id
    JOIN `cards` c ON ug.`id_organization` = c.`id_organization`
    JOIN links l ON o.id = l.`id_organization`
    JOIN `usage` u ON l.`id_usage` = u.`id`
    JOIN `businesses` b ON b.id = l.id_business
    JOIN `sites` s ON o.id = s.id_organization
    LEFT JOIN `businesses` b2 ON b2.`id` = b.`id_parent`
    LEFT JOIN `businesses` b3 ON b3.`id` = b2.`id_parent`
    LEFT JOIN `businesses` b4 ON b4.`id` = b3.`id_parent`
WHERE o.publish = 'Y'
     AND 189 IN (
                l.`id_business`,
                b.`id_parent`,
                b2.`id_parent`,
                b3.`id_parent`,
                b4.`id_parent`
                )                             
GROUP BY ug.`id_organization`
ORDER BY ug.id_package DESC, o.date_create
LIMIT 100, 10
EXPLAIN стал лучше - вместо 106000 перебирается 1200 - используется меньшая таблица ug:
id    select_type    table    type    key    key_len    ref    rows    Extra
1    SIMPLE    o    ref        publish    4    const    1290    Using where; Using temporary; Using filesort
1    SIMPLE    ug    ref        FK_usage_group_organiuzation    4    test.o.id    1    
1    SIMPLE    l    ref        FK_links_organizations_id    4    test.o.id    1    
1    SIMPLE    b    eq_ref        PRIMARY    4    test.l.id_business    1    
1    SIMPLE    b2    eq_ref        PRIMARY    4    test.b.id_parent    1    
1    SIMPLE    b3    eq_ref        PRIMARY    4    test.b2.id_parent    1    
1    SIMPLE    b4    eq_ref        PRIMARY    4    test.b3.id_parent    1    Using where
1    SIMPLE    s    ref        FK_sites_organization    5    test.l.id_organization    1    Using where
1    SIMPLE    u    eq_ref        PRIMARY    4    test.l.id_usage    1    Using index
1    SIMPLE    c    ref        FK_cards_organization    5    test.ug.id_organization    7    Using where; Using index
Время выполнения уменьшилось на 0.05 сек, но filesort остался и все равно медленно?
Можно ли еще ускорить?
Неактивен

eq_ref - это хороший способ составления таблиц в JOIN. Он имеет отношение
к JOIN `usage` u ON l.`id_usage` = u.`id`, например. Но он не имеет отношения
к фильтрации данных, которые есть 189 in (...) и вследствие которого есть
"using where" справа от нескольких колонок.
Попробуйте переписать его в виде
WHERE b.id_parent = 189 OR ...
При этом после добавления на b ключика на (id_parent, id) должно летать.
Неактивен
paulus написал:
eq_ref - это хороший способ составления таблиц в JOIN. Он имеет отношение
к JOIN `usage` u ON l.`id_usage` = u.`id`, например. Но он не имеет отношения
к фильтрации данных, которые есть 189 in (...) и вследствие которого есть
"using where" справа от нескольких колонок.
Попробуйте переписать его в виде
WHERE b.id_parent = 189 OR ...
При этом после добавления на b ключика на (id_parent, id) должно летать.
Вы будете удивлены, но использование:
WHERE o.publish = 'Y'
     AND (
                          l.`id_business` = 189
        OR b.`id_parent` = 189
        OR b2.`id_parent` = 189
        OR b3.`id_parent` = 189
        OR b4.`id_parent` = 189
        )
никак не повлияло на скорость, а ключик на b (id_parent, id) никак не повлиял на скорость и даже никак не изменил EXPLAIN.
Хотя в теории я с вами согласен. Может быть новая версия MySQL стала использовать индексы на IN выражениях..
0.16 сек предел на свободном сервере, а на рабочем 1.00 - 5.00 сек 
Есть ли смысл оптимизировать дальше? Или копаться в настройках сервера MySQL ?
Неактивен
Более того, если убрать все b - b4 и условия с ними связанные, то на производительсность это не отражается. Мне кажется ключ лежит в ORDER BY, который использует filesort.
Неактивен

Оптимизатор решил, что INDEX_MERGE в данном случае будет хуже FTS. Возможно, 
он прав 
Можете сделать табличку "предки бизнеса", где держать всех предков каждого
бизнеса (не только прямых родителей). Тогда будет один INNER JOIN, который
точно пробивает по индексу. 
P.S. MySQL умеет использовать индексы в случае с IN, когда Вы пишете
column IN (value list), но не в обратном случае.
Неактивен

А в случае без b причина может быть другой. Например, Вы достаете почти
все данные из таблицы. При этом у Вас сортировка заведомо происходит не
по индексу, т.к. сортируете Вы по двум разным таблицам. 
Есть шанс использовать сортировку по ключу для первого прохода.
Можете попробовать поиграть с JOIN, вытаскивая их в заданном Вами порядке
(SELECT STRAIGHT_JOIN ...). Если вытаскивать сначала из ug и объединять
все остальные таблицы через eq_ref, то MySQL может использовать индекс по
ug (который, разумеется, должен быть).
Неактивен
Еще интересный факт - чистая выборка всех в данном дереве занимает 0.02 сек. Т.е. надо наверное выдвинуть ее наперед.
SELECT    
    b.name b_name
FROM 
    `businesses` b
    LEFT JOIN `businesses` b2 ON b2.`id` = b.`id_parent`
    LEFT JOIN `businesses` b3 ON b3.`id` = b2.`id_parent`
    LEFT JOIN `businesses` b4 ON b4.`id` = b3.`id_parent`
WHERE  (
         b.id = 189
        OR b.`id_parent` = 189
        OR b2.`id_parent` = 189
        OR b3.`id_parent` = 189
        OR b4.`id_parent` = 189
        )
LIMIT 100, 10
10 rows fetched (0,02 sec)
Я плохо знаю как пользоваться STRAIGHT_JOIN  Буду пробовать..
 Буду пробовать..
Неактивен

Просто пишете STRAIGHT_JOIN после SELECT - и таблицы будут собираться
в том порядке, который указываете Вы, а не в том, который выбирает оптимизатор.
Иногда он может ошибаться...
Неактивен
paulus написал:
Просто пишете STRAIGHT_JOIN после SELECT - и таблицы будут собираться
в том порядке, который указываете Вы, а не в том, который выбирает оптимизатор.
Иногда он может ошибаться...
Выигрыш 0.04 секунды на лицо - спасибо.
Наверное это предел 0.11 сек для такого громоздкого запроса. Или еще остались способы? 
Неактивен

Способ - переделать сами данные. Сделайте таблицу, все-таки, с предками. Один JOIN
будет работать с индексом при ограничении WHERE, сейчас у Вас все равно выбираются
все строки, а потом идет поиск по этой временной табличке.
Неактивен
paulus написал:
Способ - переделать сами данные. Сделайте таблицу, все-таки, с предками. Один JOIN
будет работать с индексом при ограничении WHERE, сейчас у Вас все равно выбираются
все строки, а потом идет поиск по этой временной табличке.
Это я к сожалению сделать не смогу - не в моей компетенции изменение структуры таблиц. С деревом завязано много другого.
STRAIGHT_JOIN - отличная штука!
Неактивен

Тогда посмотрите еще на значение tmp_table_size. Если оно достаточно большое,
то временные таблицы будут создаваться в памяти, что несколько ускорит Ваши
запросы (я имею в виду production-машинку).
Неактивен
paulus написал:
Тогда посмотрите еще на значение tmp_table_size. Если оно достаточно большое,
то временные таблицы будут создаваться в памяти, что несколько ускорит Ваши
запросы (я имею в виду production-машинку).
Всего на машинке 512М, а tmp_table_size=32М. Есть ли смысл увеличивать?
Неактивен

Не имеет, разумеется. Осторожно с большим количеством таких запросов, а то из памяти очень
быстро выбьетесь.
Неактивен