как оптимизировать

Amen

Новичок
как оптимизировать

подскажите как оптимизировать запрос ?

сам запрос :
[sql]
SELECT SQL_CALC_FOUND_ROWS U.UserID
FROM users U
LEFT JOIN sessions S ON U.UserID = S.SessionUserID
LEFT JOIN cities_around CA ON U.UserCityID = CA.RelatedCityID
LEFT JOIN users_fetishes_options FE ON U.UserID = FE.UserID
LEFT JOIN users_body_parts_options BP ON U.UserID = BP.UserID
LEFT JOIN users_relationships_options RS ON U.UserID = RS.UserID
WHERE UserApproved != '4'
AND UserSeekingGender = '1'
AND UserGender = '2'
AND UserDateOfBirth <= '1990-02-10'
AND UserDateOfBirth >= '1972-02-15'
AND users_fetishes_options.UserOptionID
IN (
'1'
)
AND users_body_parts_options.UserOptionID
IN (
'5'
)
AND users_relationships_options.UserOptionID
IN (
'2', '5'
)
AND (
users.UserApproved = '1'
OR users.UserID = '57871'
)
GROUP BY users.UserID
ORDER BY UserMembershipID DESC
LIMIT 0 , 10
[/sql]

EXPLAIN :
Код:
id 	select_type 	table 	                                   type     	possible_keys 	key 	                        key_len       ref 	                       rows 	           Extra
1 	SIMPLE 	users_body_parts_options 	ref 	UserID,UserOptionID 	UserOptionID 	    1 	       const 	                       152111 	Using where; Using temporary; Using filesort
1 	SIMPLE 	users_fetishes_options      ref 	UserID,UserOptionID 	UserID 	                4 	       sevgilimol.BP.UserID 	1 	Using where
1 	SIMPLE 	users_relationships_options	ref 	UserID,UserOptionID 	UserID 	                4 	       sevgilimol.FE.UserID 	2 	Using where
1 	SIMPLE 	users                            eq_ref 	PRIMARY,UserDateOfBirth 	PRIMARY   4 	       sevgilimol.RS.UserID 	1 	Using where
1 	SIMPLE 	sessions                  ref 	SessionUserID 	SessionUserID      4 	       sevgilimol.FE.UserID 	32 	Using index
1 	SIMPLE 	cities_around          ref 	RelatedCityID 	RelatedCityID                   1 	        sevgilimol.U.UserCityID 	81 	Using index

show create :

Код:
Table 	Create Table
users 	CREATE TABLE `users` (\n
`UserID` int(8) unsigned NOT NULL auto_increment,\n
`UserMembershipID` enum('1','2','3') NOT NULL default '1',\n
`UserMembershipExpire` date NOT NULL default '0000-00-00',\n
`UserHighlightExpire` date NOT NULL default '0000-00-00',\n
`UserUsername` varchar(15) NOT NULL default '',\n
`UserPassword` varchar(15) NOT NULL default '',\n
`UserPasswordQuestion` enum('0','1','2','3','4','5','6','7') NOT NULL default '0',\n
`UserPasswordAnswer` varchar(32) NOT NULL default '',\n
`UserGender` enum('1','2','3') NOT NULL default '1',\n
`UserDateOfBirth` date NOT NULL default '0000-00-00',\n
`UserEmail` varchar(50) NOT NULL default '',\n
`UserEmailNotifications` enum('0','1') NOT NULL default '1',\n
`UserCountryID` tinyint(3) unsigned NOT NULL default '0',\n
`UserCityID` tinyint(3) unsigned NOT NULL default '0',\n
`UserStatus` enum('0','1','2','3','4','5') NOT NULL default '0',\n
`UserBodyType` enum('0','1','2','3','4','5','6') NOT NULL default '0',\n
`UserHeight` tinyint(3) unsigned NOT NULL default '3',\n
`UserEyeColor` enum('0','1','2','3','4','5','6') NOT NULL default '0',\n
`UserHairColor` enum('0','1','2','3','4','5','6','7') NOT NULL default '0',\n
`UserSexuallyAre` enum('0','1','2','3','4','5','6','7','8') NOT NULL default '0',\n
`UserFetishes` enum('0','1','2','3','4','5','6','7','8','9','10','11') NOT NULL default '0',\n
`UserHaveACar` enum('0','1','2','3') NOT NULL default '0',\n
`UserIncome` enum('0','1','2','3','4','5','6') NOT NULL default '0',\n
`UserHaveWebcam` enum('0','1','2') NOT NULL default '0',\n
`UserDrink` enum('0','1','2','3') NOT NULL default '0',\n
`UserSmoke` enum('0','1','2','3') NOT NULL default '0',\n
`UserSeekingGender` enum('0','1','2','3') NOT NULL default '0',\n
`UserSeekingAgesFrom` tinyint(2) unsigned NOT NULL default '0',\n
`UserSeekingAgesTo` tinyint(2) unsigned NOT NULL default '0',\n
`UserRating` double(3,2) unsigned NOT NULL default '7.00',\n
`UserMessagesSent` tinyint(3) unsigned NOT NULL default '0',\n
`UserWinksSent` tinyint(3) unsigned NOT NULL default '0',\n
`UserHomePageProfile` enum('0','1') NOT NULL default '0',\n
`UserMainImage` enum('0','1') NOT NULL default '0',\n
`UserVideo` enum('0','1','2','3') NOT NULL default '0',\n
`UserChatModerator` enum('0','1') NOT NULL default '0',\n
`UserChatTime` int(4) unsigned NOT NULL default '0',\n
`UserApproved` enum('0','1','2','3','4') NOT NULL default '0',\n
`UserRefer` varchar(50) NOT NULL default '',\n
`UserLastLogin` datetime NOT NULL default '0000-00-00 00:00:00',\n
`UserLastUpdate` datetime NOT NULL default '0000-00-00 00:00:00',\n
`UserRegistered` datetime NOT NULL default '0000-00-00 00:00:00',\n
`UserProfileUpdated` enum('0','1') NOT NULL default '0',\n
PRIMARY KEY  (`UserID`),\n
KEY `UserUsername` (`UserUsername`),\n
KEY `UserCityID` (`UserCityID`)\n
) ENGINE=MyISAM AUTO_INCREMENT=57872 DEFAULT CHARSET=latin1
 

Gas

может по одной?
Форматирование потрясает.
1. Отформатируй запрос (теги code или sql) и жедаетльно explain,
2. кинь show create table `users`
3. поставть перед всеми полями алиасы таблиц, чтоб мы не гадали.

-~{}~ 06.02.08 14:14:

Теперь бы ещё пункты 2 и 3.
4. сколько записей в таблице users
5. зачем джойнятся таблицы sessions и cities_around, как-то смысла не вижу.
 

Amen

Новичок
4. в таблице примерно 360000 записей
5. Сешшон джоинятся для того чтобы выбрать онлайн пользователей
а cities_around для фильтра по определенным городам

П.С. не понял немного , честно говоря , пункт 3.
 

Gas

может по одной?
Судя по количеству индексов в `users` и такому where
рекомендую прочитать
http://dev.mysql.com/doc/refman/5.0/en/mysql-indexes.html

сделай для начала чтоб таблица users была в explain'e первой.

а cities_around для фильтра по определенным городам
ну условий то по городам нет - зачем джойнить?

Сешшон джоинятся для того чтобы выбрать онлайн пользователей
как-то странно всё устроено, rows в explain = 32, а речь об онлайне.

не понял немного , честно говоря , пункт 3.
не перед всеми полями есть название таблицы, к которой поле принадлежит, а знать это важно, ты знаешь что у тебя где, мы то не знаем, догадаться примерно можно - но зачем гадать.
 

Amen

Новичок
Gas

Щас пробую сделать Юзерс первой . как раз над этим работаю,знаний не хватает сделать быстро.

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

-~{}~ 06.02.08 15:26:

не получается , переместить на первое место юзерс , как примерно это модно сделать ?
 

Gas

может по одной?
добавить правильный составной индекс.
 

Amen

Новичок
вот

Код:
id 	select_type 	table 	type 	possible_keys 	key 	key_len 	ref 	rows 	Extra
1 	SIMPLE 	U 	range 	PRIMARY,UserGender,UserDateOfBirth 	UserGender 	5 	NULL 	24481 	Using where; Using temporary; Using filesort
1 	SIMPLE 	FE 	ref 	UserID,UserOptionID 	UserID 	4 	sevgilimol.U.UserID 	1 	Using where
1 	SIMPLE 	RS 	ref 	UserID,UserOptionID 	UserID 	4 	sevgilimol.U.UserID 	2 	Using where
1 	SIMPLE 	BP 	ref 	UserID,UserOptionID 	UserID 	4 	sevgilimol.RS.UserID 	2 	Using where
1 	SIMPLE 	S 	ref 	SessionUserID 	SessionUserID 	4 	sevgilimol.U.UserID 	32 	Using index
1 	SIMPLE 	CA 	ref 	RelatedCityID 	RelatedCityID 	1 	sevgilimol.U.UserCityID 	81 	Using index
 

Gas

может по одной?
После каждого изменения постишь сюда:
1. изменения в индексах, какие были добавлены или удалены.
2. explain запроса.
3. как изменилась скорость запроса.

пока есть только 2.
 

Amen

Новичок
1. добавил составной индекс
UserGender
UserDateOfBirth
UserSeekingGender
UserApproved

3. скорость запроса с 5 секунд упала до 0.3

появился вопрос : будет ли работать этот индекс если выпадет одно из перчисленных полей в индексе из where ?
 

Gas

может по одной?
Тут нужно определить какие условия будут всегда во всех запросах, они точно должны быть в составном индексе, причём в порядке - чем больше уникальность значений в поле, там оно должно быть ближе к началу составного индекса. Может даже понадобиться несколько разных индексов, в зависимости от возможный сочетаний условий.

А кинь сюда результат запроса:
[sql]show index from `users`;[/sql]

To all
Не уверен, что будут использоваться части индекса UserSeekingGender и UserApproved при условии вида

WHERE UserGender=M AND UserDateOfBirth > Date AND UserSeekingGender=F AND UserApproved=1

Так-как range по UserDateOfBirth, правильно ?
 

Amen

Новичок
[sql]
SHOW INDEX FROM `users` ;
[/sql]

Код:
Table 	Non_unique 	Key_name 	Seq_in_index 	Column_name 	Collation 	Cardinality 	Sub_part 	Packed 	Null 	Index_type 	Comment
users 	0 	PRIMARY 	1 	UserID 	A 	358951 	NULL 	NULL 	  	BTREE 	 
users 	1 	UserUsername 	1 	UserUsername 	A 	358951 	NULL 	NULL 	  	BTREE 	 
users 	1 	UserGender 	1 	UserGender 	A 	3 	NULL 	NULL 	  	BTREE 	 
users 	1 	UserGender 	2 	UserDateOfBirth 	A 	17947 	NULL 	NULL 	  	BTREE 	 
users 	1 	UserGender 	3 	UserSeekingGender 	A 	23930 	NULL 	NULL 	  	BTREE 	 
users 	1 	UserGender 	4 	UserApproved 	A 	39883 	NULL 	NULL 	  	BTREE 	 
users 	1 	UserDateOfBirth 	1 	UserDateOfBirth 	A 	12819 	NULL 	NULL 	  	BTREE 	 
users 	1 	UserGender_2 	1 	UserGender 	A 	3 	NULL 	NULL 	  	BTREE 	 
users 	1 	UserGender_2 	2 	UserCountryID 	A 	325 	NULL 	NULL 	  	BTREE 	 
users 	1 	UserGender_2 	3 	UserCityID 	A 	559 	NULL 	NULL 	  	BTREE 	 
users 	1 	UserGender_2 	4 	UserApproved 	A 	1233 	NULL 	NULL 	  	BTREE
-~{}~ 06.02.08 17:39:

написал скрипт который вставляет нужные джойны , все запросы выполняются по 0.08 - 0.1 секунды , но если без лишних джойнов , то это все равно много...
 

Gas

может по одной?
Попробуй изменить порядок полей в составном ключе, чтоб они шли по уменьшению cardinality (если по полям выполняется точное совпадение "="), а то с gender'а в самом начале толку мало.

Для запроса из первого поста лучше ключ по:
(UserApproved, UserSeekingGender, UserGender, UserDateOfBirth)
можно попробовать ещё UserID в конец добавить, может от Using temporary избавит. Дело то скорее именно Using temporary; Using filesort. А от Using filesort тут похоже никак не уйти.

http://dev.mysql.com/doc/refman/5.0/en/query-speed.html
 

Amen

Новичок
Gas спасиб за помощь .

Еще один вопрос , как избавиться от цифр в Extra Session 32 , Cities_around 81.

проход идет по индексу , в табилицах всего два поля и по каждому индекс.
 

Gas

может по одной?
Только не extra, а rows - это среднее число записей, для пользователя. По-этому и странно что простым джойном таблицы sessions определяется online. Using index - это хорошо, если джойн этих таблиц на скорость не влияет, тогда и не парься, если влияет - напиши, и тогда стоит посмотреть влазит создаваемая temporary table в память или сохраняется на диск.
 

Amen

Новичок
Gas

Да rows , ошибся , съехала таблица :)

На данный момент скорость запросов в промежутке 0.008 - 0.1 с.

0.1 приходится в основном на момент , когда джоинятся вместе таблицы session и cities .

раз проходит по индексу , не совсем понятно почему на каждую запись из users выбираеться 32 из sessions и 81 из cities.
 

Gas

может по одной?
Таблица sessions просто джойнится без условий вообще? Тогда если всё крутится не на продакшене или посещаемость не большая, запускай до и после поиска
show status like 'Created_tmp_%';
и смотри увеличивается значение "Created_tmp_disk_tables", если да - пробуй увеличить системную переменную mysql - tmp_table_size. А лучше вообще изменить логику определения online.

Что касается cities - не джойнить если нет условия, если условие по нему появляется ( = или IN ), то добавить на эту таблицу составную индекс (RelatedCityID, _поле(я) по которым есть доп условие_).
 

Amen

Новичок
Gas
Сенк :)

-~{}~ 07.02.08 15:26:

Хм...

Нет , и sessions и cities джоинятся при условиях .
Неполучается сделать составной индекс как вы предлагаете
(RelatedCityID, _поле(я) по которым есть доп условие_).
потому что в табилице Сити только два поля.
Или я вас не правильно понял?
 

Gas

может по одной?
в табилице Сити только два поля.
поле RelatedCityID и поле "Ы". правильно?

cities джоинятся при условиях
под условием, я понимаю условие по полю "Ы". Если такого условия нет (как запрос в твоём перовом посте) - не вижу смысла джойнить cities, разве значение U.UserCityID может не существовать в cities ?
Если есть условие по полю "Ы" - добавь в cities составной индекс (`RelatedCityID`,`Ы`)
 
Сверху