2016-09-20 3 views
2

В настоящее время для моего сайта в моих статьях есть теги на них.mysql, что бы было быстрее

Когда я Переберите список статей, для каждого из них я сделать запрос MySQL, чтобы собрать список категорий теги для них, как так:

SELECT c.`category_name`, c.`category_id` 
FROM `articles_categorys` c 
    INNER JOIN `article_category_reference` r ON c.category_id = r.category_id 
WHERE r.article_id = 8136 
ORDER BY r.`category_id` = *IDHERE* DESC, r.`category_id` ASC 
LIMIT 4 

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

То, что я решил сделать, это сделать массив всех article_ids на странице, а затем сделать это вместо:

SELECT c.`category_name`, c.`category_id`, r.article_id 
FROM `articles_categorys` c 
INNER JOIN `article_category_reference` r ON c.category_id = r.category_id 
WHERE r.article_id = 8136 OR r.article_id = 8130 OR r.article_id = 8127 
    OR r.article_id = 8125 OR r.article_id = 8123 OR r.article_id = 8120 
    OR r.article_id = 8119 OR r.article_id = 8117 OR r.article_id = 8116 
    OR r.article_id = 8112 OR r.article_id = 8107 OR r.article_id = 8106 
    OR r.article_id = 8037 OR r.article_id = 8104 OR r.article_id = 8103 

Затем я использую PHP просто перебрать массив найденных из вышеприведенного, сопрягать article_id для текущей статьи, и если она соответствует echo category_name. Единственная проблема - теперь я не могу ограничить ее до 4 в article_id.

Является ли более новый подход лучше, хуже, или оба сосут ужасно?

Пример данных для использования:

CREATE TABLE `articles_categorys` (
    `category_id` int(11) NOT NULL, 
    `category_name` varchar(32) COLLATE utf8_bin NOT NULL 
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin; 

CREATE TABLE `article_category_reference` (
    `ref_id` int(11) NOT NULL, 
    `article_id` int(11) NOT NULL, 
    `category_id` int(11) NOT NULL 
) ENGINE=MyISAM DEFAULT CHARSET=latin1; 

INSERT INTO `articles_categorys` (`category_id`, `category_name`) VALUES 
(22, 'Site Info'), 
(1, 'Editorial'), 
(2, 'Review'), 
(3, 'Interview'), 
(4, 'Game Sale'), 
(5, 'Steam'), 
(6, 'Indie Game'), 
(7, 'Crowdfunding'), 
(8, 'Game Bundle'), 
(9, 'Free Game'), 
(10, 'MMO'); 

INSERT INTO `article_category_reference` (`ref_id`, `article_id`, `category_id`) VALUES 
(15, 6231, 22), 
(14, 6231, 1), 
(16, 6231, 2), 
(17, 6231, 3), 
(18, 6231, 4), 
(19, 6231, 9), 
(20, 6231, 10); 
+0

Попробуйте 'WHERE r.article_id IN (8136, 8130, 8127, .......)' – RiggsFolly

+0

У вас есть сердце IN()? –

+0

SQL-запрос, как правило, является узким местом любой веб-страницы, поэтому наиболее важным решением является наличие одного большого (но умного!) Запроса. Не забудьте «ORDER BY r.article_id» сгруппировать теги в результате, он сохранит код. –

ответ

1

С SQL, всегда хорошо тестировать и выполнять EXPLAIN в ваших запросах, чтобы увидеть, что будет быстрее. Но, как правило, IN, вероятно, превосходит несколько OR. Это все еще оставляет вам проблему с ограничением результатов до четырех. Вопреки тому, что было сказано в комментариях, неплохо получить все данные, а затем выбрать только 4 элемента, используя PHP. Вы можете потенциально извлекать тысячи строк только для отображения сотни.

SET @rank=null, @val=null; 
SELECT * FROM (

    SELECT c.`category_name`, c.`category_id`, r.article_id, 
    @rank := IF(@val = r.article_id, @rank+1,1) as rank, 
    @val := r.article_id 
    FROM `articles_categorys` c 
    INNER JOIN `article_category_reference` r ON c.category_id = r.category_id 
    WHERE r.article_id IN (8136, /* fill this up accordingly */) 

    ORDER BY r.`category_id` ASC 
) AS a WHERE rank < 5; 

Для получения более подробной информации см это превосходное Q & A: Using LIMIT within GROUP BY to get N results per group?

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

+0

Это действительно интересно, никогда не видел ничего подобного! Вы дали мне что-то новое, чтобы посмотреть, и, похоже, он работает именно так, как я хочу этого, поэтому я считаю это правильным решением. – NaughtySquid

+0

Фактически, сейчас я делаю некоторые фактические тесты живых данных, и он, кажется, не ограничивает его до 4. Я вынул «ORDER BY r.'category_id' = * IDHERE * DESC», потому что я не знаете, что вы имели в виду, у нас нет идентификатора категории, мы захватываем его в самом запросе. Кажется, все они имеют ранг 1. – NaughtySquid

+0

Каков хороший способ получить некоторые данные из моей таблицы в мой вопрос с лучшим форматированием? – NaughtySquid

0

иногда не достаточно просто сделать хороший запрос, вы должны использовать параметры SQL. Чтобы быстрее выполнять ваши запросы, вы должны использовать индексы (например, хэш или btree) или уникальные значения https://www.tutorialspoint.com/mysql/mysql-indexes.htm.

Смежные вопросы