这个查询非常简单,我要做的就是按last_updated
字段对给定类别中的所有文章进行排序:
SELECT
`articles`.*
FROM
`articles`,
`articles_to_categories`
WHERE
`articles`.`id` = `articles_to_categories`.`article_id`
AND `articles_to_categories`.`category_id` = 1
ORDER BY `articles`.`last_updated` DESC
LIMIT 0, 20;
但是它运行非常缓慢。这是EXPLAIN所说的:
select_type table type possible_keys key key_len ref rows Extra
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SIMPLE articles_to_categories ref article_id,category_id article_id 5 const 5016 Using where; Using temporary; Using filesort
SIMPLE articles eq_ref PRIMARY PRIMARY 4 articles_to_categories.article_id 1
有没有一种方法可以重写此查询或向我的PHP脚本中添加其他逻辑,以避免Using temporary; Using filesort
并加快速度?
表结构:
*articles*
id | title | content | last_updated
*articles_to_categories*
article_id | category_id
更新
我已经last_updated
索引了。我想我的情况在文档中得到了解释:
在某些情况下,MySQL无法使用索引来解析ORDER BY,尽管它仍然使用索引来查找与WHERE子句匹配的行。这些情况包括:
用于获取行的键与在ORDER BY中使用的键不同:SELECT * FROM t1 WHERE key2 = constant ORDER BY
key1;您正在联接许多表,并且ORDER BY中的列并非全部来自用于检索行的第一个非恒定表。(这是EXPLAIN输出中的第一个没有const
join类型的表。)
但我仍然不知道如何解决此问题。
这是我之前为类似性能相关问题所做的一个简化示例,该问题利用了innodb集群主键索引(显然仅适用于innodb!)。
您有3个表:category,product和product_category,如下所示:
drop table if exists product;
create table product
(
prod_id int unsigned not null auto_increment primary key,
name varchar(255) not null unique
)
engine = innodb;
drop table if exists category;
create table category
(
cat_id mediumint unsigned not null auto_increment primary key,
name varchar(255) not null unique
)
engine = innodb;
drop table if exists product_category;
create table product_category
(
cat_id mediumint unsigned not null,
prod_id int unsigned not null,
primary key (cat_id, prod_id) -- **note the clustered composite index** !!
)
engine = innodb;
最重要的是 product_catgeory集群复合主键 的 顺序, 因为在这种情况下,典型的查询总是以(x,y,z
…)中的cat_id = x或cat_id开头。
我们有 50万个 类别, 100万个 产品和 1.25亿个 产品类别。
select count(*) from category;
+----------+
| count(*) |
+----------+
| 500000 |
+----------+
select count(*) from product;
+----------+
| count(*) |
+----------+
| 1000000 |
+----------+
select count(*) from product_category;
+-----------+
| count(*) |
+-----------+
| 125611877 |
+-----------+
因此,让我们看看该架构如何对与您的查询相似的查询执行。所有查询都在空缓冲区且无查询缓存的情况下冷运行(在mysql重新启动后)。
select
p.*
from
product p
inner join product_category pc on
pc.cat_id = 4104 and pc.prod_id = p.prod_id
order by
p.prod_id desc -- sry dont a date field in this sample table - wont make any difference though
limit 20;
+---------+----------------+
| prod_id | name |
+---------+----------------+
| 993561 | Product 993561 |
| 991215 | Product 991215 |
| 989222 | Product 989222 |
| 986589 | Product 986589 |
| 983593 | Product 983593 |
| 982507 | Product 982507 |
| 981505 | Product 981505 |
| 981320 | Product 981320 |
| 978576 | Product 978576 |
| 973428 | Product 973428 |
| 959384 | Product 959384 |
| 954829 | Product 954829 |
| 953369 | Product 953369 |
| 951891 | Product 951891 |
| 949413 | Product 949413 |
| 947855 | Product 947855 |
| 947080 | Product 947080 |
| 945115 | Product 945115 |
| 943833 | Product 943833 |
| 942309 | Product 942309 |
+---------+----------------+
20 rows in set (0.70 sec)
explain
select
p.*
from
product p
inner join product_category pc on
pc.cat_id = 4104 and pc.prod_id = p.prod_id
order by
p.prod_id desc -- sry dont a date field in this sample table - wont make any diference though
limit 20;
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+----------------------------------------------+
| 1 | SIMPLE | pc | ref | PRIMARY | PRIMARY | 3 | const | 499 | Using index; Using temporary; Using filesort |
| 1 | SIMPLE | p | eq_ref | PRIMARY | PRIMARY | 4 | vl_db.pc.prod_id | 1 | |
+----+-------------+-------+--------+---------------+---------+---------+------------------+------+----------------------------------------------+
2 rows in set (0.00 sec)
因此,那是0.70秒的寒冷-哎呀。
希望这可以帮助 :)
编辑
刚刚阅读完您对以上评论的答复,看来您可以选择以下两种选择之一:
create table articles_to_categories
(
article_id int unsigned not null,
category_id mediumint unsigned not null,
primary key(article_id, category_id), -- good for queries that lead with article_id = x
key (category_id)
)
engine=innodb;
要么。
create table categories_to_articles
(
article_id int unsigned not null,
category_id mediumint unsigned not null,
primary key(category_id, article_id), -- good for queries that lead with category_id = x
key (article_id)
)
engine=innodb;
取决于您有关如何定义群集PK的 典型 查询。
本文向大家介绍如何避免MySQL查询中的OR语句过多?,包括了如何避免MySQL查询中的OR语句过多?的使用技巧和注意事项,需要的朋友参考一下 使用MySQL避免太多的OR语句。让我们首先创建一个表- 使用插入命令在表中插入一些记录- 使用select语句显示表中的所有记录- 这将产生以下输出- 以下是避免在MySQL查询中使用太多OR语句的查询,即使用- 这将产生以下输出-
问题内容: 首先导入k和模块: 声明和对象: 有三个表:和。该Artist对象可以链接到多个。并且该Album对象可以链接到多个对象。的是保持之间的关系和紧密的: 所以我们有Artist链接到Album这是与Genre它看起来像这样:。 完成此设置后,我们Genre首先创建对象: 然后是两张专辑: 和艺术家: 创建数据库后,我们可以查询Albums链接到的内容Genre: 以及Artists链接到
问题内容: Context 当函数返回aTABLE或a时,例如以下示例函数: 可以通过多种方法访问结果: 1)将产生以下输出列: 2)select func(3)将仅产生ROW类型的一个输出列。 unc (1,3) (2,9) (3,27) i Ĵ — +- 1 | 3 2 | 9 3 | 27 select N, (func(N)).* from (select 2 as N union sel
问题内容: 我正在使用以下代码通过AJAX提交表单: 背景 我的PHP处理程序执行各种任务,然后发回响应。然后,我可以在成功或错误函数中执行某些操作。 我的问题 当用户双击表单的“提交”按钮时,将发生两次AJAX调用,这将导致我的PHP处理程序中的代码执行两次。 我的问题 如果用户双击提交,如何避免我的代码执行两次? 问题答案: 当AJAX调用再次出现时,请先禁用首次单击的“提交”按钮,然后重新启
问题内容: 级联正是CSS变得特别而强大的原因。但在媒体查询的情况下,重叠 可 似乎有问题。 考虑以下CSS(CSS媒体查询重叠的连续规则): 因此,当屏幕正好为45em宽时,将根据标准CSS级联来处理45em处的重叠: 所有定义都将首先应用, 并将在此之后全部应用。 请考虑以下两个条件: 通常,所有文本都是,但是 查询A 是唯一的并且具有。 由于 查询B 适用于较大的视口,因此其文本具有CSS
问题内容: 我遇到了麻烦。 有一个实体发行人与与实体镇的ManyToMany关系有关: 那么实体镇也与地区有关 现在,我必须过滤(使用jpql)一个区域中的所有分发服务器。我能怎么做? 问题答案: 请参阅:https://en.wikibooks.org/wiki/Java_Persistence/JPQL