Модераторы: skyboy

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> оптимизировать запрос 
V
    Опции темы
solenko
Дата 28.8.2009, 17:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1473
Регистрация: 15.1.2006
Где: Украина

Репутация: 4
Всего: 67



Здравствуйте. Есть запрос:
Код

SELECT TilesAttributes.extractDate, Country.CountryID as ObjectID, Country.FullName as Name,
    SUM(TilesAttributes.tier1APs) as tier1APs,
    SUM(TilesAttributes.tier2APs) as tier2APs,
    SUM(TilesAttributes.tier3APs) as tier3APs,
    SUM(TilesAttributes.tier1Cells) as tier1Cells,
    SUM(TilesAttributes.tier2Cells) as tier2Cells
FROM TilesAttributes
    RIGHT JOIN Tiles ON Tiles.TileID = LEFT(TilesAttributes.tileId,6)
    LEFT JOIN TileMetro ON Tiles.TileID = TileMetro.TileID
    LEFT JOIN Metro ON Metro.MetroID = TileMetro.MetroID
    LEFT JOIN Country ON Country.CountryID = Metro.CountryID
WHERE
    TilesAttributes.extractDate >= '2009-07-02' AND
    Country.CountryID = '2'
GROUP BY TilesAttributes.extractDate
ORDER BY NULL;


Структуру таблиц, думаю, приводить нет смысла. Все суммируемые колонки unsigned int.
Время выполнения запроса -- 40 секунд. Профайлер показывает что все это время расходуется на копирование в tmp таблицу. 
Можно ли уменьшить время выполнения запроса?

explain для запроса:
Код

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: Country
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: Using temporary
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: TilesAttributes
         type: ALL
possible_keys: PRIMARY,extractDate_idx
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 3454552
        Extra: Using where
*************************** 3. row ***************************
           id: 1
  select_type: SIMPLE
        table: Tiles
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 34
          ref: func
         rows: 1
        Extra: Using where; Using index
*************************** 4. row ***************************
           id: 1
  select_type: SIMPLE
        table: TileMetro
         type: ref
possible_keys: TileRegion,TileID
          key: TileID
      key_len: 34
          ref: func
         rows: 1
        Extra: Using where
*************************** 5. row ***************************
           id: 1
  select_type: SIMPLE
        table: Metro
         type: eq_ref
possible_keys: PRIMARY,CountryID
          key: PRIMARY
      key_len: 4
          ref: dms.TileMetro.MetroID
         rows: 1
        Extra: Using where
5 rows in set (0.00 sec)



--------------------
Ла-ла-ла-ла
Заметьте, нет официального подтверждения, что это не просто четыре слога.
PM MAIL WWW ICQ Skype   Вверх
gcc
Дата 30.8.2009, 01:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Агент алкомафии
****


Профиль
Группа: Участник
Сообщений: 2691
Регистрация: 25.4.2008
Где: %&й

Репутация: 3
Всего: 17



 smile индексы посмотреть может не срабатывают, может стоит создать тестовую базу и протестировать с разыми вариантами...?
PM WWW ICQ Skype GTalk Jabber   Вверх
solenko
Дата 31.8.2009, 06:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1473
Регистрация: 15.1.2006
Где: Украина

Репутация: 4
Всего: 67



Индекс не используется для where по TilesAttributes.extractDate >= '2009-07-02' (почему я так и не понял, но суть в том, что сама выборка занимает ничтожно малое время). Видимо MySQL выбирает full scan из-за малой селективности индекса и большого колическтва данных, подходящих под условие (из 3*10^6 строк подходят 2.5*10^6).
А разные варианты я, естественно, пробовал -- результата пока нет. Получалось тольку увеличивать время на 2 секунды ))


--------------------
Ла-ла-ла-ла
Заметьте, нет официального подтверждения, что это не просто четыре слога.
PM MAIL WWW ICQ Skype   Вверх
DimW
Дата 31.8.2009, 07:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1330
Регистрация: 24.2.2005
Где: Орёл

Репутация: 4
Всего: 44



это:
Цитата(solenko @  28.8.2009,  17:39 Найти цитируемый пост)
Время выполнения запроса -- 40 секунд


как то не сходится с этим:
Цитата(solenko @  31.8.2009,  06:34 Найти цитируемый пост)
выборка занимает ничтожно малое время


и что за tmp таблица у вас, в скрипте про нее ничего не сказано.
PM MAIL ICQ   Вверх
solenko
Дата 31.8.2009, 07:38 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1473
Регистрация: 15.1.2006
Где: Украина

Репутация: 4
Всего: 67



Цитата(DimW @  31.8.2009,  06:11 Найти цитируемый пост)
как то не сходится с этим:

еще как сходится. В процессе выполения запроса данные не только выбираются, но и сортируются, группируются и т.д.
Цитата(DimW @  31.8.2009,  06:11 Найти цитируемый пост)
и что за tmp таблица у вас, в скрипте про нее ничего не сказано.

о ней сказано в explain -- результат выполнения запроса (или его части) mysql размещает во временной таблице. В идеале это таблица с engyne memory, но если не хватает мета в памяти, то данные сбрасываются на диск в myisam таблицу.


--------------------
Ла-ла-ла-ла
Заметьте, нет официального подтверждения, что это не просто четыре слога.
PM MAIL WWW ICQ Skype   Вверх
DimW
Дата 31.8.2009, 07:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1330
Регистрация: 24.2.2005
Где: Орёл

Репутация: 4
Всего: 44



Цитата(solenko @  31.8.2009,  07:38 Найти цитируемый пост)
о ней сказано в explain

где? ткните пальцем.


Цитата(solenko @  31.8.2009,  07:38 Найти цитируемый пост)
В идеале это таблица с engyne memory, но если не хватает мета в памяти, то данные сбрасываются на диск в myisam таблицу. 

вы что действительно считаете что результатом милионной выборки является засранная память и tmp таблица на диске? если не трудно ссылочкой поделитесь где описан этот процесс.

Цитата(solenko @  31.8.2009,  07:38 Найти цитируемый пост)
 но и сортируются

а сортировка по null это фича mysql?  smile
PM MAIL ICQ   Вверх
solenko
Дата 31.8.2009, 08:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1473
Регистрация: 15.1.2006
Где: Украина

Репутация: 4
Всего: 67



Цитата(DimW @  31.8.2009,  06:55 Найти цитируемый пост)
где? ткните пальцем.

Код

*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: Country
         type: const
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: const
         rows: 1
        Extra: Using temporary

Цитата(DimW @  31.8.2009,  06:55 Найти цитируемый пост)
вы что действительно считаете что результатом милионной выборки является засранная память и tmp таблица на диске? если не трудно ссылочкой поделитесь где описан этот процесс.

А вы считаете что данные , с которыми работает сервер размещается в небесном эфире, а не в оперативке?
Четко описанного процесса выполнения запроса сейчас не найду, но подверждение своих слов:
http://dev.mysql.com/doc/refman/5.0/en/using-explain.html
Цитата

To resolve the query, MySQL needs to create a temporary table to hold the result. This typically happens if the query contains GROUP BY and ORDER BY clauses that list columns differently.

Цитата(DimW @  31.8.2009,  06:55 Найти цитируемый пост)
а сортировка по null это фича mysql?

Это борьба с фисей MySQL. MySQL по умолчанию сортирует данные по столбцу группировки (т.е. к using temparary добавится еще и filesort). Ну а order by null позволяет этого избежать


--------------------
Ла-ла-ла-ла
Заметьте, нет официального подтверждения, что это не просто четыре слога.
PM MAIL WWW ICQ Skype   Вверх
DimW
Дата 31.8.2009, 08:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1330
Регистрация: 24.2.2005
Где: Орёл

Репутация: 4
Всего: 44



Цитата(solenko @  31.8.2009,  08:18 Найти цитируемый пост)
А вы считаете что данные , с которыми работает сервер размещается в небесном эфире, а не в оперативке?

да нет конечно, просто я всегда считал что для того чтобы вернуть результат не обязательно дожидаться формирования результат всего запроса. за инфу спасибо, почитаю.

Цитата(solenko @  31.8.2009,  08:18 Найти цитируемый пост)
Это борьба с фисей MySQL

извиняюсь что влезаю с вопросами в вашу тему, просто хочу пронять - это борьба с сортировкой до group by(имеется ввиду сортировка вспомогательная для group by) или mysql типа так заботится о разработчике пологая, что сгруперованные данные понадобятся сортированными?

Цитата(solenko @  31.8.2009,  08:18 Найти цитируемый пост)
        Extra: Using temporary

ага, увидел.

Цитата(solenko @  28.8.2009,  17:39 Найти цитируемый пост)
Время выполнения запроса -- 40 секунд.

а время выполнения запроса  о котором вы говорите это время от запуска запроса до получения их на клиенте, просто в плане об этом времени ничего не сказано.

Добавлено через 9 минут и 17 секунд
Цитата(DimW @  31.8.2009,  08:43 Найти цитируемый пост)
для того чтобы вернуть результат 

сори за формулеровку, имел ввиду не ВЕРНУТЬ, а НАЧАТЬ ВОЗВРАЩАТЬ.
PM MAIL ICQ   Вверх
solenko
Дата 31.8.2009, 08:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1473
Регистрация: 15.1.2006
Где: Украина

Репутация: 4
Всего: 67



Цитата(DimW @  31.8.2009,  07:43 Найти цитируемый пост)
извиняюсь что влезаю с вопросами в вашу тему, просто хочу пронять - это борьба с сортировкой до group by(имеется ввиду сортировка вспомогательная для group by) или mysql типа так заботится о разработчике пологая, что сгруперованные данные понадобятся сортированными?

после group by. 
//Мне тоже иногда кажется, что разработчики слишком заботливы )
Цитата(DimW @  31.8.2009,  07:43 Найти цитируемый пост)
а время выполнения запроса  о котором вы говорите это время от запуска запроса до получения их на клиенте, просто в плане об этом времени ничего не сказано. 

это непосредственно время выполнения (отчет о времени по данным самого сервера). Прикрепил полный профайл запроса.

Присоединённый файл ( Кол-во скачиваний: 1 )
Присоединённый файл  query_profile.txt 9,13 Kb


--------------------
Ла-ла-ла-ла
Заметьте, нет официального подтверждения, что это не просто четыре слога.
PM MAIL WWW ICQ Skype   Вверх
Akina
Дата 31.8.2009, 08:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 106
Всего: 454



Цитата(solenko @  28.8.2009,  18:39 Найти цитируемый пост)
Структуру таблиц, думаю, приводить нет смысла. 

И всё=таки дай запрос формирования таблиц, а? достаточно оставить только значимые поля и существующие индексы. 
Тогда можно просто залить его в БД и покрутить. А так, на пальцах, муторно... А воссоздавать просто влом.


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
solenko
Дата 31.8.2009, 09:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1473
Регистрация: 15.1.2006
Где: Украина

Репутация: 4
Всего: 67



прикрепил sql с структурой

Ну и данные по количеству строк в таблицах:
Код

SELECT count( * ) FROM Country;

count( * )
252
------------------------------
SELECT COUNT( * ) FROM Metro;

COUNT( * )
261
------------------------------
SELECT COUNT( * ) FROM TileMetro;

COUNT( * )
33953
------------------------------
SELECT COUNT( * ) FROM Tiles;

COUNT( * )
33953
------------------------------
SELECT COUNT( * ) FROM TilesAttributes;

COUNT( * )
3454552





Присоединённый файл ( Кол-во скачиваний: 4 )
Присоединённый файл  table_structure.sql 3,44 Kb


--------------------
Ла-ла-ла-ла
Заметьте, нет официального подтверждения, что это не просто четыре слога.
PM MAIL WWW ICQ Skype   Вверх
Zloxa
Дата 31.8.2009, 09:21 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

Репутация: 33
Всего: 161



Цитата(solenko @  31.8.2009,  06:34 Найти цитируемый пост)
Видимо MySQL выбирает full scan из-за малой селективности индекса и большого колическтва данных, подходящих под условие 

Не совсем Вы правильно поняли.
Чем выше селективность предиката отбора, тем  больший процент данных данных возвращается запросом. При селективности предиката отбора = 1 возвращается весь набор данных. По предикату с селективностью = 0 не будет произведено отбора вовсе.
Соответственно Вы имеете предикат с высокой селективностью, не с низкой.
В вашем случае селективность = 0,83(3) и это действительно очень большая селективность и индексный доступ не будет эффективным.
Однако это лишь пол беды.
У Вас ведь есть еще один предикат отбора - CountryID = '2', о селективности которого Вы умолчали.
В альтернативном плане, можно было бы использовать как лидирующую таблицу отбор из Metro по CountryId = 2, подтянуть Tiles и, следом отфильтроваться по TilesAttributes.
Однако этот план не осуществим изза того что критерий объединения использует функцию:
Код
Tiles.TileID = LEFT(TilesAttributes.tileId,6)

По этому критерию Tiles не может быть ведущей для TilesAttributes, только ведомой.

Ну и еще замечание. В Вашем запросе критерии отбора применяются к соединенным полям. Это приводит к тому, что все outer join, прописанные в запросе вырождается в inner. Думаю оптимизатор это понимает и Вам не удалось его запутать. Но чтобы не запутаться самому и не запутывать тех, кто будет в последствии разбирать Ваш запрос, было бы неплохо заменить outer join на inner, там где он таковым является на самом деле.

Это сообщение отредактировал(а) Zloxa - 31.8.2009, 09:23


--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
solenko
Дата 31.8.2009, 09:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1473
Регистрация: 15.1.2006
Где: Украина

Репутация: 4
Всего: 67



Цитата(Zloxa @  31.8.2009,  08:21 Найти цитируемый пост)
Не совсем Вы правильно поняли.

Понял то правильно, авот в терминах (малая эффективность/малая селективность) напутал.
Цитата(Zloxa @  31.8.2009,  08:21 Найти цитируемый пост)
У Вас ведь есть еще один предикат отбора - CountryID = '2', о селективности которого Вы умолчали.


Код

SELECT COUNT( * ) 
FROM TilesAttributes
INNER JOIN Tiles ON Tiles.TileID = LEFT( TilesAttributes.tileId, 6 ) 
INNER JOIN TileMetro ON Tiles.TileID = TileMetro.TileID
INNER JOIN Metro ON Metro.MetroID = TileMetro.MetroID
INNER JOIN Country ON Country.CountryID = Metro.CountryID
WHERE Country.CountryID = '2'

Код

COUNT(*) 
91115

Цитата(Zloxa @  31.8.2009,  08:21 Найти цитируемый пост)
По этому критерию Tiles не может быть ведущей для TilesAttributes, только ведомой.

А есть где-то описание всего списка критериев, по которым таблица (не)может быть ведущей?

Цитата(Zloxa @  31.8.2009,  08:21 Найти цитируемый пост)
Ну и еще замечание. В Вашем запросе критерии отбора применяются к соединенным полям. Это приводит к тому, что все outer join, прописанные в запросе вырождается в inner. 

Да, тут inner и по логике, и по сути. Естественно будт изменены. Спасибо.

Добавлено через 7 минут
Цитата(Zloxa @  31.8.2009,  08:21 Найти цитируемый пост)
В альтернативном плане, можно было бы использовать как лидирующую таблицу отбор из Metro по CountryId = 2, подтянуть Tiles и, следом отфильтроваться по TilesAttributes.

Я таки идиот. Добавил TileID6 -- первые шесть символов из tileId и создал по нему индекс:
Код

SELECT TilesAttributes.extractDate, Country.CountryID AS ObjectID, Country.FullName AS Name, SUM( TilesAttributes.tier1APs ) AS tier1APs, SUM( TilesAttributes.tier2APs ) AS tier2APs, SUM( TilesAttributes.tier3APs ) AS tier3APs, SUM( TilesAttributes.tier1Cells ) AS tier1Cells, SUM( TilesAttributes.tier2Cells ) AS tier2Cells
FROM TilesAttributes
INNER JOIN Tiles ON Tiles.TileID = TilesAttributes.TileID6
INNER JOIN TileMetro ON Tiles.TileID = TileMetro.TileID
INNER JOIN Metro ON Metro.MetroID = TileMetro.MetroID
INNER JOIN Country ON Country.CountryID = Metro.CountryID
WHERE TilesAttributes.extractDate >= '2009-07-02'
AND Country.CountryID = '2'
GROUP BY TilesAttributes.extractDate
ORDER BY NULL

Время выполнения 2 секунды.

Спасибо. Но по поводу ведущих/ведомых таблиц вопрос остается актуальным.


--------------------
Ла-ла-ла-ла
Заметьте, нет официального подтверждения, что это не просто четыре слога.
PM MAIL WWW ICQ Skype   Вверх
Zloxa
Дата 31.8.2009, 10:12 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

Репутация: 33
Всего: 161



Цитата(solenko @  31.8.2009,  09:47 Найти цитируемый пост)

А есть где-то описание всего списка критериев, по которым таблица (не)может быть ведущей?

Честно говоря не уверен, что это гдето явно описано, но логика ведь проста. Tiles.TileID может быть получен из TilesAttributes.tileId однако вычислить TilesAttributes.tileId из Tiles.TileID  невозможно, потому Tiles не может быть ведущей.

Существуют рекомендации(так называемые Best Pracrtice) по возможности не использовать функции от значений полей в критериях объединения и отбора

Это сообщение отредактировал(а) Zloxa - 31.8.2009, 10:19


--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
Zloxa
Дата 31.8.2009, 10:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Чо?
****


Профиль
Группа: Завсегдатай
Сообщений: 3473
Регистрация: 12.9.2008

Репутация: 33
Всего: 161



Цитата(DimW @  31.8.2009,  08:43 Найти цитируемый пост)
mysql типа так заботится о разработчике пологая, что сгруперованные данные понадобятся сортированными?

Я тоже долго ржал когда впервые вычитал. Полагаю изначально группировка могла выполняться только через сортировку, потому сортировку при группировке задокументировали и даже добавили модификаторы ASC, DESC. А потом пришлось тянуть функционал для обратной совместимости и придумывать нелепые воркэраунды, чтобы избежать оверхеда.
Цитата

#

If you use GROUP BY, output rows are sorted according to the GROUP BY columns as if you had an ORDER BY for the same columns. To avoid the overhead of sorting that GROUP BY produces, add ORDER BY NULL:

SELECT a, COUNT(b) FROM test_table GROUP BY a ORDER BY NULL;

#

MySQL extends the GROUP BY clause so that you can also specify ASC and DESC after columns named in the clause:

SELECT a, COUNT(b) FROM test_table GROUP BY a DESC;





--------------------
Достоверно известно, что 89% людей доверяют статистике взятой с потолка smile
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | MySQL | Следующая тема »


 




[ Время генерации скрипта: 0.0643 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.