Форум: Форум PHPФорум ApacheФорум Регулярные ВыраженияФорум MySQLHTML+CSS+JavaScriptФорум FlashРазное
Новые темы: 0000000
Самоучитель PHP 5 / 6 (3 издание). Авторы: Кузнецов М.В., Симдянов И.В. MySQL 5. В подлиннике. Авторы: Кузнецов М.В., Симдянов И.В. Самоучитель MySQL 5. Авторы: Кузнецов М.В., Симдянов И.В. PHP 5. На примерах. Авторы: Кузнецов М.В., Симдянов И.В., Голышев С.В. PHP на примерах (2 издание). Авторы: Кузнецов М.В., Симдянов И.В.
ВСЕ НАШИ КНИГИ
Консультационный центр SoftTime

Форум MySQL

Выбрать другой форум

 

Здравствуйте, Посетитель!

вид форума:
Линейный форум Структурный форум

тема: Оптимизация запросов с JOIN
 
 автор: Unreal   (09.01.2007 в 03:56)   письмо автору
 
 

Доброго времени суток, пишу страницу которая выводит следующие данные:

Исполнитель (имя), его альбомы (с годами), стиль, жанр, похожие артисты
другая страница с альбомом этого исполнителя:
Исполнитель (имя), Название альбома, всего времени в альбоме, список песен, жанр, стиль, похожие артисты
Структура таблиц (дамп, и их вид) представлены во вложенном файле.

На основании скипрта который тут приводили, сделал немного другой и с помощью него смотрю скорость обработки запросов:

<?php
function gettime()
{
    
$part_time explode(' 'microtime());
    
$realtime $part_time[1].substr($part_time[0],1);
    return 
$realtime;
}
$id_singer '79';
$id_album '';
$id_style '45';

$sql[] = "SELECT DISTINCT(file.id_genre),name_genre FROM file LEFT JOIN genre ON file.id_genre=genre.id_genre WHERE id_singer='$id_singer';";  
$sql[] = "SELECT DISTINCT(file.id_style),name_style FROM file LEFT JOIN style ON file.id_style=style.id_style WHERE id_singer='$id_singer';";
$sql[] = "SELECT DISTINCT(file.id_singer),singer.name_singer FROM file LEFT JOIN singer ON file.id_singer=singer.id_singer WHERE id_style='$id_style' ORDER BY RAND() LIMIT 20;";

mysql_connect('localhost','root','8520');
mysql_select_db('music');
$start_time gettime();

$indexLimit count($sql);
for (
$index=0$index $indexLimit$index++) {
    
mysql_query($sql[$index]);
}

$stop_time gettime();
$total bcsub($stop_time$start_time2); 

print 
"Execution time: ".$total;
?>


есть еще другие запросы, но их время выполнения 0.02, если добавить эти три, то время выполнения возрастает до 1.04 секунды.
Этими запросам выбирается:
1) id жанра, название жанра - (0.32)
2) id стиля, название стиля (0.34)
3) id исполнителя, имя исполнителя (0.34)

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

   
 
 автор: cheops   (09.01.2007 в 12:46)   письмо автору
 
   для: Unreal   (09.01.2007 в 03:56)
 

Такая скорость на сервере или на локальной машине?

   
 
 автор: Unreal   (09.01.2007 в 12:53)   письмо автору
 
   для: cheops   (09.01.2007 в 12:46)
 

локальный компьютер, Core Duo 2 итд, возможно проблема в неверном проектировании таблиц или числе записей в них?

Число записей по таблицам:

album - 39945
file - 468977
genre - 18
singer - 11684
style - 342

   
 
 автор: cheops   (09.01.2007 в 13:06)   письмо автору
 
   для: Unreal   (09.01.2007 в 12:53)
 

Тогда всё нормально... MySQL не настраивали, сколько Мб под неё выделено? Жёсткий диск IDE или SATA - шина на материнской плате одна? Компьютер регулярно выключаете? В результате кэши индексов и запросов (даже такие маленькие, которые выделены по умолчанию) постоянно обнуляются...

Нужно тестировать на рабочем сервере, локальная машина, даже очень мощная - это не показатель... MySQL расчитана на большую нагрузку. У меня дома этот форум по минуте открывается, хотя машина не слабая и только под MySQL выделено пол-гигабайта памяти. Но так как посетителей нет - кэши не заполнены и производительность хуже некуда.

   
 
 автор: Unreal   (09.01.2007 в 13:41)   письмо автору
 
   для: cheops   (09.01.2007 в 13:06)
 

У хостера тоже самое, проблема в том что страниц много (например по тем же исполнителям 11684) и все они разные, выборка совершенно разная будет и врятле там что-то скешируется, потому что shared hosting, серваки у хостера мощные, но много разных запросов идет от разных сайтов .

Пробовал специально взять Apache Bench и запустить его на одну и ту же страницу (на домашнем компе), для начала поставил 100 запросов к странице, действительно у MySQL hitrate поднялся почти до 100%. Это было бы приемлимо если бы эту страницу постоянно грузили, но как я писал выше, для каждого исполнителя создается новая страница.

Диск Seagate Barracuda 10000 rpm SATA, 1 Gb памяти, винда ставилась недавно, всякими экспериментами с софтом не занимаюсь, глюкавые програмки не ставлю, работаю админом, так что дома на эксперименты не тянет :) MySQL действительно был запущен с дефолтным конфигом по той причине что хотел написать приложение быстрое, а не надеятся на скорость компа.

Сейчас запустил MySQL с конфигом my-huge.ini по всем запросам Query Cache Hitrate взлетел до 100%, Key Efficience - 100%, скорость отдачи страниц в Apache Bench естественно поднялась кроме вот этого запроса:

<?php 
$sql
[] = "SELECT DISTINCT(file.id_singer),singer.name_singer FROM file LEFT JOIN singer ON file.id_singer=singer.id_singer WHERE id_style='$id_style' ORDER BY RAND() LIMIT 20;";
?>
хотя оно и понятно, т.к. в нем ORDER BY RAND

Приложил файл с небольшим дампом с данными, в нем данные по одному исполнителю.


UPD:
cheops, вы правы насчет скорости загрузки, она действительно очень возрастает при загрузке одной и той же страницы (в моем случае получается по одним запросам). Попробовал сейчас убрать ORDER BY RAND() и снова натравить Apache Bench, скорость загрузки страниц со всеми 8ю запросами выросла до 48ms. Просто я думал что может это я запросы неправильно строю, и поэтому так медленно все работает. Хотелось бы выжать все что можно из MySQL при помощи оптимизации запросов или изменения структуры таблиц не принимая во внимание кэширование запросов...

   
 
 автор: Trianon   (09.01.2007 в 13:14)   письмо автору
 
   для: Unreal   (09.01.2007 в 03:56)
 

а индексы по полям с id_ами построены?

DISTINCT - вообще злая вещь....

   
 
 автор: Unreal   (09.01.2007 в 13:46)   письмо автору
 
   для: Trianon   (09.01.2007 в 13:14)
 

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

   
 
 автор: Trianon   (09.01.2007 в 14:42)   письмо автору
 
   для: Unreal   (09.01.2007 в 13:46)
 

В аттаче первого сообщения дамп структуры. И индексов, кроме первичных, там таки невидно.

   
 
 автор: Unreal   (09.01.2007 в 15:13)   письмо автору
 
   для: Trianon   (09.01.2007 в 14:42)
 

Я не очень разбираюсь в этом, знаю только что если на строке стоит Primary Key то она выбирается быстрее. Подскажите что тогда можно изменить в этих таблицах?

   
 
 автор: Trianon   (09.01.2007 в 15:42)   письмо автору
 
   для: Unreal   (09.01.2007 в 15:13)
 

Создать индексы на остальных id_... полях
например, у таблицы file, помимо первичного ключа id_file (индекс для которого уже создан автоматически) нужно создать индексы для полей id_singer, id_album, id_style,id_genre, по сути своей представляющих чужие ключи.

ALTER TABLE `file` ADD INDEX ( `id_singer` );
ALTER TABLE `file` ADD INDEX ( `id_album` );
ALTER TABLE `file` ADD INDEX ( `id_style` );
ALTER TABLE `file` ADD INDEX ( `id_genre` );

Так же и с другими таблицами.

   
 
 автор: Unreal   (09.01.2007 в 16:04)   письмо автору
 
   для: Trianon   (09.01.2007 в 15:42)
 

Огромное спасибо :-)

Ваш совет действительно помог, даже с дефолтным конфигом от MySQL все 8 запросов выполняются за 0.10 сек

   
Rambler's Top100
вверх

Rambler's Top100 Яндекс.Метрика Яндекс цитирования