简体   繁体   English

mysql 什么会更快

[英]mysql what would be faster

Currently for my website, my articles have tags on them.目前对于我的网站,我的文章上有标签。

When I loop through the list of articles, for each one I do a mysql query to gather a list of category tags for them like so:当我遍历文章列表时,对于每篇文章,我都会执行一个 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

Now, imagine a page where I have say 30 articles shown at once, the above query would be done 30 times.现在,想象一个页面,我说一次显示 30 篇文章,上面的查询将执行 30 次。 I imagine that's terrible.我想那太可怕了。

What I decided to do was make an array of all the article_ids on a page and then do this instead:我决定做的是在页面上创建一个包含所有 article_id 的数组,然后执行以下操作:

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

I then use PHP just to loop through the array found from the above, match the article_id to the current article to them and if it matches echo the category_name.然后我使用 PHP 循环遍历从上面找到的数组,将 article_id 与当前文章匹配到它们,如果匹配则回显 category_name。 The only problem is now I can't limit it to 4 per article_id.唯一的问题是现在我不能将每个 article_id 限制为 4 个。

Is the newer approach better, worse, or do both suck horribly?较新的方法是更好,更糟,还是两者都糟糕透了?

Example data to use:要使用的示例数据:

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);

With SQL, it's always good to benchmark and do an EXPLAIN on your queries to see which will be faster.使用 SQL,对您的查询进行基准测试和 EXPLAIN 以查看哪个会更快总是好的。 But as a rule of thumb, IN will probably outperform multiple ORs.但根据经验,IN 可能会胜过多个 OR。 That still leaves you with the problem of limiting the results to four each.这仍然给您留下了将结果限制为每个四个的问题。 Contrary to what's been said in the comments, it's not a good idea to fetch all the data and then choose only 4 items using PHP.与评论中所说的相反,获取所有数据然后使用 PHP 仅选择 4 个项目并不是一个好主意。 You could potentially be retrieving thousands of rows only to display a hundred.您可能会检索数千行只显示一百行。

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;

For more details, see this excellent Q&A: Using LIMIT within GROUP BY to get N results per group?有关更多详细信息,请参阅此优秀问答: 在 GROUP BY 中使用 LIMIT 以获得每组 N 个结果?

In short, what this query does is to asign a rank to each record.简而言之,该查询的作用是为每条记录分配一个等级。 At the start the rank is null, for the first row it will be set to null.开始时等级为空,第一行将设置为空。 While the r.category_id remains the same it will keep on increasing but would drop back to one when the category_id changes.虽然 r.category_id 保持不变,但它会继续增加,但当 category_id 更改时会回落到 1。

sometimes not enough to just make good query, you must use SQL options.有时不足以进行良好的查询,您必须使用 SQL 选项。 To make your queries faster you should use indices (such as hash or btree) or unique values https://www.tutorialspoint.com/mysql/mysql-indexes.htm .为了使您的查询更快,您应该使用索引(例如哈希或 btree)或唯一值https://www.tutorialspoint.com/mysql/mysql-indexes.htm

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM