首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >如何改进此查询?

如何改进此查询?
EN

Database Administration用户
提问于 2013-05-14 11:29:11
回答 3查看 170关注 0票数 3

大约一年前,我介绍了一个查询,它返回一种“客户也购买”数据集。然而,在它运行得相当快的时候,它变得非常慢,有时甚至需要5秒或更长的时间。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT p.*, COUNT(*) AS total
FROM orders_products AS op
JOIN products AS p ON p.products_id = op.products_id
JOIN (
  SELECT orders_id
  FROM orders_products
  WHERE products_id = 100
) AS opf ON opf.orders_id = op.orders_id
WHERE op.products_id <> 100
GROUP BY products_id
ORDER BY total DESC
LIMIT 5;

产自explain extended

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
+------+-------------+-----------------+--------+-----------------------+-------------+---------+------------------------------------+------+----------+---------------------------------+
| id   | select_type | table           | type   | possible_keys         | key         | key_len | ref                                | rows | filtered | Extra                           |
+------+-------------+-----------------+--------+-----------------------+-------------+---------+------------------------------------+------+----------+---------------------------------+
|    1 | SIMPLE      | orders_products | ref    | products_id,orders_id | products_id | 4       | const                              | 4511 |   100.00 | Using temporary; Using filesort |
|    1 | SIMPLE      | op              | ref    | products_id,orders_id | orders_id   | 4       | database.orders_products.orders_id |    2 |   100.00 | Using where                     |
|    1 | SIMPLE      | p               | eq_ref | PRIMARY               | PRIMARY     | 4       | database.op.products_id            |    1 |   100.00 |                                 |
+------+-------------+-----------------+--------+-----------------------+-------------+---------+--------------------------------------+------+----------+-------------------------------+

SHOW CREATE TABLE products

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
+----------+----------------------------------------------------------------+
| Table    | Create Table                                                   
+----------+----------------------------------------------------------------+
| products | CREATE TABLE `products` (
  `products_id` int(11) NOT NULL AUTO_INCREMENT,
  `products_model` varchar(128) DEFAULT NULL,
  `products_price` decimal(15,4) NOT NULL DEFAULT '0.0000',
  `products_date_added` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
  `products_last_modified` datetime DEFAULT NULL,
  `products_status` tinyint(1) NOT NULL DEFAULT '0',
  PRIMARY KEY (`products_id`),
  KEY `idx_products_date_added` (`products_date_added`),
  KEY `products_model` (`products_model`),
  KEY `products_price` (`products_price`),
  KEY `products_status` (`products_status`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+----------+----------------------------------------------------------------+

SHOW INDEXES FROM products

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
+----------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table    | Non_unique | Key_name                         | Seq_in_index | Column_name                | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+----------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| products |          0 | PRIMARY                          |            1 | products_id                | A         |        4356 |     NULL | NULL   |      | BTREE      |         |               |
| products |          1 | idx_products_date_added          |            1 | products_date_added        | A         |        4356 |     NULL | NULL   |      | BTREE      |         |               |
| products |          1 | products_model                   |            1 | products_model             | A         |        4356 |     NULL | NULL   | YES  | BTREE      |         |               |
| products |          1 | products_price                   |            1 | products_price             | A         |        1089 |     NULL | NULL   |      | BTREE      |         |               |
| products |          1 | products_status                  |            1 | products_status            | A         |           4 |     NULL | NULL   |      | BTREE      |         |               |
+----------+------------+----------------------------------+--------------+----------------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

SHOW CREATE TABLE orders_products

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
+-----------------+--------------------------------------------------------+
| Table           | Create Table                                           
+-----------------+--------------------------------------------------------+
| orders_products | CREATE TABLE `orders_products` (
  `orders_products_id` int(11) NOT NULL AUTO_INCREMENT,
  `orders_id` int(11) NOT NULL DEFAULT '0',
  `products_id` int(11) NOT NULL DEFAULT '0',
  PRIMARY KEY (`orders_products_id`),
  KEY `products_id` (`products_id`),
  KEY `orders_id` (`orders_id`),
) ENGINE=InnoDB DEFAULT CHARSET=utf8 |
+-----------------+--------------------------------------------------------+

SHOW INDEXES FROM orders_products

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
+-----------------+------------+-------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table           | Non_unique | Key_name    | Seq_in_index | Column_name        | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-----------------+------------+-------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| orders_products |          0 | PRIMARY     |            1 | orders_products_id | A         |     3134198 |     NULL | NULL   |      | BTREE      |         |               |
| orders_products |          1 | products_id |            1 | products_id        | A         |        5014 |     NULL | NULL   |      | BTREE      |         |               |
| orders_products |          1 | orders_id   |            1 | orders_id          | A         |     1567099 |     NULL | NULL   |      | BTREE      |         |               |
+-----------------+------------+-------------+--------------+--------------------+-----------+-------------+----------+--------+------+------------+---------+---------------+

有什么明显的东西我错过了吗?在大多数方面,数据库似乎经过了很好的调整。我们正在InnoDB/XtraDB存储引擎下运行MariaDB 5.5.30。

EN

回答 3

Database Administration用户

回答已采纳

发布于 2013-05-14 12:25:02

这个表(orders_products)是一个多对多的表.我认为在这样的表上有2个复合索引是很常见的,因为它在许多常见的查询中都有帮助。

我肯定会在(orders_id, products_id)(products_id, orders_id)上添加两个(唯一的)索引。

不确定是否将两者都定义为UNIQUE将是MariaDB优化器的进一步改进。

如果没有什么特殊的原因,可以删除自动递增的orders_products_id列。您可以通过订单和产品in标识表中的行。我认为该列只会在表和索引中增加更多的空间,而不会增加值。

票数 5
EN

Database Administration用户

发布于 2013-05-14 12:22:17

我不知道你的数据库,但希望这能帮上忙

我设置了一些测试数据,因此我有一个包含27,000行数据的orders_products表,因此,我可以从一个可能的10组中随机获得三个条目。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Create Table orders_products (Orders_Id Number, Products_Id Number);
create index orders_products_I1 on orders_products(orders_id);
create index orders_products_I2 on orders_products(products_id);

我假设您没有像Oracle这样的复合键,所以只创建了两个索引,每个索引都有一个id。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
Declare 
 P_Id Number(3);
 o_id Number(4);
Begin
  For o_id In 1000..9999
  Loop
     P_Id:=trunc(dbms_random.value(1,9))*100;
     insert into orders_Products values (o_id, p_id);
     P_Id:=trunc(dbms_random.value(1,9))*100;
     Insert Into Orders_Products Values (O_Id, P_Id);
     P_Id:=trunc(dbms_random.value(1,9))*100;
     Insert Into Orders_Products Values (O_Id, P_Id);
  End Loop;
  Commit;
END;

这就是我如何在Oracle中重写您的查询的方法,它只获取项和计数的列表

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
select p.* from products_id
 where products_id in ( 
     select products_id
       From Orders_Products Op
      where op.orders_id in (select orders_id 
                               from orders_products opf
                              Where Exists (Select 1 
                                              from orders_products ope
                                             Where Products_Id=100)
                            ) 
         And Op.Products_Id <> 100
       Group By Products_Id
       order by count(*) desc)
   and rownum <=5

这在一秒钟内运行(运行时间: 00:00:00.234),如果使用绑定变量而不是硬编码products_id,那么在Oracle中每次运行速度都会更快,因此如果数据库中有绑定变量,这可能会有所帮助。如果您已经存在,它只需要找到第一个事件,而不是所有可能匹配的事件。

我忽略的唯一一点是选择项目的所有产品详细信息--可以在此查询的外部放置一个包装器,以便只返回您想要的5个产品的所有产品详细信息,而不是根据排序限制所有行的详细信息。

这是包含总数的内部查询的结果。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
PRODUCTS_ID TOTAL
----------- -----
    700  3486 
    600  3406 
    400  3393 
    300  3389 
    200  3322 
    800  3320 
    500  3309 

Elapsed: 00:00:00.234

这是排除它的结果,所以我们可以在外部选择中使用products_id。

PRODUCTS_ID

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
    700 
    600 
    400 
    300 
    200 
    800 
    500 

经过: 00:00:00.405

票数 1
EN

Database Administration用户

发布于 2013-05-14 12:09:13

第一个操作看起来很昂贵,警告标志是Using temporary; Using filesort。考虑在orders_products上添加一个允许在products_id上搜索的索引:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
create index IX_OrdersProcucts_ProductId
    on orders_products(products_id, orders_id);

通过在orders_id之外添加products_id,索引将覆盖:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
SELECT orders_id
FROM orders_products
WHERE products_id = 100

如果添加此索引,则explain extended输出的第一步应包括Using index

票数 0
EN
页面原文内容由Database Administration提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://dba.stackexchange.com/questions/42188

复制
相关文章
Python算法解析:寻找最短路径!
最短路径算法用于在图中找到两个节点之间的最短路径。最短路径问题在许多实际应用中都有重要的作用,例如网络路由、导航系统等。
测试开发囤货
2023/08/08
6490
Python算法解析:寻找最短路径!
java算法之寻找最小的k个数--1
1.快排,不讲了 2.定义一个小根堆,比如priorityqueue,添加数据,利用小根堆每次弹出最小值即可
名字是乱打的
2021/12/22
2610
Prim算法生成最小生成树
由一个带权值的联通图到一个最小生成树的过程,其实就是从图的所有边中挑出一部分边用来组成树的过程,所以关键在于如何挑选边。
叶茂林
2023/07/30
1920
Prim算法生成最小生成树
最短路径生成树与最小生成树
虽然放在一起,但是他们两个除了都是树之外没有一点关系。 最短路径生成树,就是ROOT根节点到达任意点距离最短的路径所构成的树,就是最短路径生成树。我画两个图给大家理解。
风骨散人Chiam
2020/10/28
1.1K0
最短路径生成树与最小生成树
图的最小生成树算法
在上一篇文章中,我们看了一下图的遍历算法,主要是对图的深度优先遍历和图的广度优先遍历算法思想的介绍。接下来让我们来看一下图的最小声成树算法。
指点
2019/01/18
2.6K0
图的最小生成树算法
最小生成树的Kruskal算法
定义: 一个有 n 个结点的连通图的生成树是原图的极小连通子图,且包含原图中的所有 n 个结点,并且有保持图连通的最少的边。[1] 最小生成树可以用kruskal(克鲁斯卡尔)算法或prim(普里姆)算法求出。 Kruskal算法简述: 假设 WN=(V,{E}) 是一个含有 n 个顶点的连通网,则按照克鲁斯卡尔算法构造最小生成树的过程为:先构造一个只含 n 个顶点,而边集为空的子图,若将该子图中各个顶点看成是各棵树上的根结点,则它是一个含有 n 棵树的一个森林。之后,从网的边集 E 中选取一条权值最小的
用户3577892
2020/06/12
2K0
最小生成树的个数_最小生成树的两种算法
设最小生成树的边权之和为 sum,严格次小生成树就是指边权之和大于 sum 的生成树中最小的一个。
全栈程序员站长
2022/09/22
9800
寻找矩阵中的路径
给定一个矩阵和一个字符串,如何从矩阵中寻找出这个字符串在矩阵中的路径?本文就跟大家分享下如何使用回溯法来解决这个问题,欢迎各位感兴趣的开发者阅读本文。
神奇的程序员
2022/04/10
1.1K0
寻找矩阵中的路径
Prim算法-最小生成树
基本思想: 1 置S={1} 2 只要S是V的真子集就做如下的贪心选择:   选取满足条件的i ,i属于S,j输入V-S,且c[i][j]最小的边,并将定点j加入S中   这个过程直到S==V为止。 3 这个过程所选的边,恰好就是最小生成树 算法描述: void Prim(int n,Type * * c) { T = 空集; S = {1}; while(S != V) { (i,j)=i 属于 S 且 j属于V-S的最小权边; T = T∪
用户1154259
2018/01/17
2.6K0
动画演示广度优先算法寻找最短路径
上一节,我们刚刚介绍了使用深度优先算法(DFS)解决迷宫问题,这一节我们来介绍广度优先算法(BFS)。BFS 算法与 DFS 十分相似,唯一的区别就是 DFS 算法使用后进先出的栈来保存节点,而 BFS 算法使用先进先出的队列来存储节点,除此之外简直就是一母同胞的亲兄弟。当然,这两种方案各有千秋。DFS 算法找到的路径往往不是最短路径,速度慢但占用内存较少,而 BFS 算法找到的总是最短路径,速度较快但占用内存较多。
用户2870857
2019/12/23
2.1K0
动画演示广度优先算法寻找最短路径
Kruskal算法-最小生成树
算法思想: 1 将G的n个顶点看成n个孤立的连通分支,所有的边按权从小到大排序 2 当查看到第k条边时,   如果断点v和w分别是当前的两个不同的连通分支t1和t2中的顶点时,就用边(v,m)j将t1,t2连接成一个连通分支,然后继续查看第k+1条边;   如果端点v和w当前的同一个连通分支中,就直接查看第k+1条边 实现代码: template <class Type> class EdgeNode{ friend ostream& operator<<(ostream&,EdgeNode<Typ
用户1154259
2018/01/17
2.1K0
☆打卡算法☆LeetCode 64、最小路径和 算法解析
链接:64. 最小路径和 - 力扣(LeetCode) (leetcode-cn.com)
恬静的小魔龙
2022/08/07
2800
☆打卡算法☆LeetCode 64、最小路径和  算法解析
图算法|Prim算法求最小生成树
01 — 一个实际问题 要在n个城市之间铺设光缆,要求有2个: 这 n 个城市的任意两个之间都可以通信; 铺设光缆的费用很高,且各个城市之间铺设光缆的费用不同,因此要使铺设光缆的总费用最低。 如下所示
double
2018/04/02
4K0
图算法|Prim算法求最小生成树
最小生成树(Kruskal算法和Prim算法)
上一篇文章,我们讲了图的创建和遍历,其中遍历的算法主要有BFS(广度优先算法)和DFS(深度优先算法)两种,并且DFS算法对很多问题都有很好的启示!而今天我们要说一个非常实用的算法——最小生成树的建立!这是图论中一个经典问题,可以使用Kruskal和Prim两种算法来进行实现!
算法工程师之路
2019/08/05
5.3K0
最小生成树算法:Kruskal 与 Prim算法
连通图中的每一棵生成树,都是原图的一个极大无环子图,即:从其中删去任何一条边,生成树就不再连通;反之,在其中引入任何一条新边,都会形成一条回路。
利刃大大
2023/04/12
2K0
最小生成树算法:Kruskal 与 Prim算法
Kruscal(最小生成树)算法模版
1 const int maxn=400;//最大点数 2 const int maxm=10000;//最大边数 3 int n,m;//n表示点数,m表示边数 4 struct edge{int u,v,w;} e[maxm];//u,v,w分别表示该边的两个顶点和权值 5 bool cmp(edge a,edge b) 6 { 7 return a.w<b.w; 8 } 9 int fa[maxn];//因为需要用到并查集来判断两个顶点是否属于同一个连通块 10 int fi
Angel_Kitty
2018/04/09
1.4K0
最小生成树-Prim算法和Kruskal算法
Prim算法 1.概览 普里姆算法(Prim算法),图论中的一种算法,可在加权连通图里搜索最小生成树。意即由此算法搜索到的边子集所构成的树中,不但包括了连通图里的所有顶点(英语:Vertex (graph theory)),且其所有边的权值之和亦为最小。该算法于1930年由捷克数学家沃伊捷赫·亚尔尼克(英语:Vojtěch Jarník)发现;并在1957年由美国计算机科学家罗伯特·普里姆(英语:Robert C. Prim)独立发现;1959年,艾兹格·迪科斯彻再次发现了该算法。因此,在某些场合,普里姆算
用户1215536
2018/02/05
3.7K0
最小生成树-Prim算法和Kruskal算法
最小路径问题 | Dijkstra算法详解(附代码)
来源:AI蜗牛车本文共3400字,建议阅读6分钟本文对Dijkstra算法做了一个详细的介绍。 一、最短路径问题介绍 1、从图中的某个顶点出发到达另外一个顶点的所经过的边的权重和最小的一条路径,称为最短路径。 2、解决问题的算法: 迪杰斯特拉算法(Dijkstra算法) 弗洛伊德算法(Floyd算法) SPFA算法 这篇文章,就先对Dijkstra算法来做一个详细的介绍~ 二、Dijkstra算介绍 算法特点 迪科斯彻算法使用了广度优先搜索解决赋权有向图或者无向图的单源最短路径问题,算法最终得到一个最短路
数据派THU
2022/05/31
5K0
最小路径问题 | Dijkstra算法详解(附代码)
最小生成树(Prim算法和Kruskal算法算法详解)
通俗易懂的讲就是最小生成树包含原图的所有节点而只用最少的边和最小的权值距离。因为n个节点最少需要n-1个边联通,而距离就需要采取某种策略选择恰当的边。
bigsai
2019/10/21
3.9K0
最小生成树(Prim算法和Kruskal算法算法详解)
最小生成树之Prim算法和Kruskal算法
一个连通图可能有多棵生成树,而最小生成树是一副连通加权无向图中一颗权值最小的生成树,它可以根据Prim算法和Kruskal算法得出,这两个算法分别从点和边的角度来解决。
业余草
2019/01/21
1.8K0
最小生成树之Prim算法和Kruskal算法

相似问题

寻找最小瓶颈路径的线性时间算法

10

算法:寻找最小倍数

11

用什么算法来寻找最小生成森林?

12

寻找选定顶点的最小生成树的算法

11

寻找算法:生成二部图的最小割集

15
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文