У меня есть сайт медиацентра, на котором я работаю, у него есть страница, отображающая категории мультимедиа. Каждая категория может иметь несколько назначенных ей элементов мультимедиа, и каждый элемент мультимедиа может быть присвоен нескольким категориям.Как упростить этот сложный запрос?
Страница содержит текстовый ввод, который должен иметь возможность фильтровать категории, которые показаны.
Что мне нужно сделать, это получить каждую категорию, связанную с текущим пользователем ($user_id
), а также элемент мультимедиа, принадлежащий этому пользователю (неиспользуемые категории не отображаются). Обычно это было бы достаточно просто, но я также должен иметь возможность фильтровать категории на основе полей в других таблицах, связанных с носителем.
поля мне нужно, чтобы иметь возможность применить текстовый фильтр следующим образом:
message_number
вmedia
таблицеkeywords
вmedia
таблицеspeaker_name
вmedia_speakers
таблицеseries_name
media_series
столbook_name
вmedia_books
таблицеcategory_name
вmedia_categories
таблице
Как теперь, запрос занимает несколько секунд. Я не профессионал MySQL, поэтому я уверен, что должны быть лучшие способы сделать то, что мне нужно сделать здесь. В случае, если это помогает, я использую MySQLi через PHP. У моего запроса есть несколько подзапросов, и я уверен, что это причина проблемы, но я не знал другого способа делать то, что я пытаюсь сделать.
Ниже приведены соответствующие структуры таблиц и текущий запрос. Я включил столько информации, сколько могу придумать, что может помочь кому-то помочь мне в этом, но если вам нужна дополнительная информация, просто дайте мне знать.
media
стол (опуская некоторые нерелевантные поля) (серия, динамик, и книжные поля содержат идентификатор записи в их соответствующих таблицах):
`id` int(10) unsigned zerofill NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`date` date NOT NULL DEFAULT '0000-00-00',
`message_number` varchar(32) DEFAULT NULL,
`series` int(10) unsigned zerofill NOT NULL DEFAULT '0000000000',
`speaker` int(10) unsigned zerofill NOT NULL DEFAULT '0000000000',
`book` int(10) unsigned zerofill NOT NULL DEFAULT '0000000000',
`keywords` text NOT NULL,
PRIMARY KEY (`id`)
media_series
стол:
`id` int(10) unsigned zerofill NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`series_name` varchar(255) NOT NULL DEFAULT '',
`cover` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
media_speakers
стол:
`id` int(10) unsigned zerofill NOT NULL AUTO_INCREMENT,
`user_id` int(11) DEFAULT NULL,
`speaker_name` varchar(255) NOT NULL DEFAULT '',
`cover` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
media_books
стола:
`id` int(10) unsigned zerofill NOT NULL AUTO_INCREMENT,
`book_name` varchar(64) NOT NULL DEFAULT '',
`book_shortname` varchar(10) NOT NULL DEFAULT '',
PRIMARY KEY (`id`)
media_categories
стола:
`id` int(10) unsigned zerofill NOT NULL AUTO_INCREMENT,
`user_id` int(11) NOT NULL,
`category_name` varchar(255) NOT NULL DEFAULT '',
`cover` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `id` (`id`)
media_categories_assoc
стола:
`id` int(11) NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned DEFAULT NULL,
`media_id` int(10) unsigned zerofill DEFAULT NULL,
`category_id` int(10) unsigned zerofill DEFAULT NULL,
`marked_for_deletion` int(1) DEFAULT '0',
PRIMARY KEY (`id`)
Наконец, чрезмерно сложные запросы:
SELECT media_categories.id `media_categories.id`,
media_categories.user_id `media_categories.user_id`,
media_categories.category_name `media_categories.category_name`,
media_categories.cover `media_categories.cover`,
(SELECT id
FROM media
WHERE user_id = '$user_id'
AND media_categories.id IN (SELECT category_id
FROM media_category_assoc
WHERE user_id = '$user_id')
ORDER BY `date` DESC
LIMIT 1) `media.id`,
(SELECT `date`
FROM media
WHERE user_id = '$user_id'
AND media_categories.id IN (SELECT category_id
FROM media_category_assoc
WHERE user_id = '$user_id')
ORDER BY `date` DESC
LIMIT 1) `media.date`,
(SELECT series
FROM media
WHERE user_id = '$user_id'
AND media_categories.id IN (SELECT category_id
FROM media_category_assoc
WHERE user_id = '$user_id')
ORDER BY `date` DESC
LIMIT 1) `media.series`,
(SELECT speaker
FROM media
WHERE user_id = '$user_id'
AND media_categories.id IN (SELECT category_id
FROM media_category_assoc
WHERE user_id = '$user_id')
ORDER BY `date` DESC
LIMIT 1) `media.speaker`
FROM media_categories
LEFT JOIN media
ON media.id IN (SELECT media_id
FROM media_category_assoc
WHERE media_id = media.id
AND user_id = '$user_id')
LEFT JOIN media_series
ON media.series = media_series.id
LEFT JOIN media_speakers
ON media.speaker = media_speakers.id
LEFT JOIN media_books
ON media.book = media_books.id
WHERE media_categories.user_id = '$user_id'
AND media_categories.id IN (SELECT category_id
FROM media_category_assoc
WHERE user_id = '$user_id')
AND (media.title LIKE '%filter_text%'
OR media.message_number LIKE '%filter_text%'
OR media.keywords LIKE '%filter_text%'
OR media_speakers.speaker_name LIKE '%filter_text%'
OR media_categories.category_name LIKE '%filter_text%'
OR media_series.series_name LIKE '%filter_text%'
OR media_books.book_name LIKE '%filter_text%')
GROUP BY `media_categories.id`
ORDER BY `media.date` DESC
LIMIT 0, 12;
Подзапросы действительно могут заставлять ваш запрос быть настолько медленным. Попробуйте подход «разделяй и властвуй»: создайте временные таблицы для «промежуточных» шагов (подзапросов), а затем соедините их ... Вы можете поместить все создание временных таблиц в хранимую процедуру, которая поможет вам определить каждый параметр запроса только один раз. Обязательно создайте все необходимые индексы в каждой временной таблице. – Barranka
Хммм ... Спасибо за подсказку. Временные таблицы звучат так, как будто это может быть полезно. Однако я не совсем уверен, как это реализовать здесь, и я не уверен, что вы подразумеваете под «необходимыми индексами». – vertigoelectric
Как мой вопрос вне темы? – vertigoelectric