Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/mysql/72.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Mysql 在主键上使用JOIN时应该使用什么索引_Mysql_Join_Indexing_Query Optimization - Fatal编程技术网

Mysql 在主键上使用JOIN时应该使用什么索引

Mysql 在主键上使用JOIN时应该使用什么索引,mysql,join,indexing,query-optimization,Mysql,Join,Indexing,Query Optimization,我正在尝试优化以下MySQL查询 SELECT Hotel.HotelId, Hotel.Name, Hotel.Enabled, Hotel.IsClosed, HotelRoom.HotelId, HotelRoom.RoomId, HotelRoom.Name AS RoomName FROM Hotel INNER JOIN HotelRoom ON Hotel.HotelId = HotelRoom.HotelId WHERE Hotel.IsClosed = 0 A

我正在尝试优化以下MySQL查询

SELECT Hotel.HotelId, Hotel.Name, Hotel.Enabled, Hotel.IsClosed, 
HotelRoom.HotelId, HotelRoom.RoomId, HotelRoom.Name AS RoomName
FROM Hotel
INNER JOIN 
   HotelRoom ON Hotel.HotelId = HotelRoom.HotelId    
WHERE Hotel.IsClosed = 0
AND Hotel.Enabled = 1
AND HotelRoom.Deleted = 0
AND HotelRoom.Enabled = 1
AND IF(LENGTH(TRIM(sAuxiliaryIds)) > 0 AND sAuxiliaryIds IS NOT NULL, 
FIND_IN_SET(Hotel.AuxiliaryId, sAuxiliaryIds), 1=1) > 0 
ORDER BY Hotel.HotelId ASC, HotelRoom.RoomId ASC
主键是Hotel.Hotel和HotelRoom.RoomId,我有一把从HotelRoom.HotelId到Hotel.HotelId的外键

我应该为WHERE子句中使用的
(Hotel.IsClosed,Hotel.Enabled)
(HotelRoom.Deleted,HotelRoom.Enabled)
创建索引吗?这个索引应该包括主键吗?例如,我应该为
(Hotel.HotelId,Hotel.IsClosed,Hotel.Enabled)

编辑1 我在WHERE语句中添加了以下内容
,如果(长度(TRIM(sAuxiliaryIds))>0且sAuxiliaryIds不为空,则在_集合中查找_(Hotel.AuxiliaryId,sAuxiliaryIds),1=1)>0
,这些是否也应包括在索引中

这是EXPLAIN语句为此查询显示的内容

我添加了两个索引建议,但当我运行EXPLAIN语句时,它们都表明不会使用任何键


这里有两种可能的索引策略,具体取决于两个表中的哪一个出现在内部联接的左侧(任何一个表都可能出现在联接的任何一侧)。考虑到
HotelRoom
表可能包含比
Hotel
表多得多的记录,我建议将
Hotel
表放在连接的左侧。这意味着将扫描
Hotel
表,以及用于加入
HotelRoom
的索引。然后,我们可以尝试在
HotelRoom
上使用以下索引:

CREATE INDEX hotel_room_idx ON HotelRoom (HotelId, Deleted, Enabled, Name, RoomId);
这将大大加快连接速度,包括
WHERE
子句,还包括
HotelRoom
上选择的所有列。请注意,以下简化索引也可能非常有效:

CREATE INDEX hotel_room_idx ON HotelRoom (HotelId, Deleted, Enabled);

这仅仅涵盖了join和
WHERE
子句,但是MySQL可能仍然选择使用它。

MySQL的优化器不关心在
join中哪个表排在第一位。它将查看统计数据(etc),自行决定是从
酒店开始,还是从
酒店房间开始。因此,您应该为这两种情况编写索引,以免限制优化器

MySQL几乎总是通过扫描一个表来执行
JOIN
。然后,对于该表中的每一行,在另一个表中查找必要的行。请参阅“嵌套循环联接”或“NLJ”。这意味着最佳索引(通常)是这样的:对于“first”表,
WHERE
子句中涉及第一个表的列。对于
第二个
表,包含涉及第二个表的
WHERE
子句上的列

假设优化器从Hotel开始:

Hotel: INDEX(IsClosed, Enabled)   -- in either order
HotelRoom:  INDEX(Deleted, Enabled, HotelId)  -- in any order
如果是从HotelRoom开始的:

HotelRoom:  INDEX(Deleted, Enabled)  -- in either order
Hotel: PRIMARY KEY(HotelId)  -- which you already have?
如果有很多关闭/残疾酒店,那么这可能是有益的:

Hotel: INDEX(IsClosed, Enabled, HotelId)
正如Tim所提到的,增加一个索引以包括所提到的其余列可能是有益的,从而使索引“覆盖”。(但不要使用
主键或任何
唯一键执行此操作。)


如果您提供了
showcreatetable
和表的大小,我们可能会有进一步的建议。

我还刚刚添加了EXPLAIN语句。对不起,你说的“我建议把旅馆的桌子放在餐厅的左边”是什么意思如果我读对了,那么目前似乎没有使用索引。如果你喜欢,你可以尝试我的建议,然后评论它是否工作。我不需要考虑一个索引<代码>酒店< /代码>表吗?对不起,没有回答你的第二个问题;我现在才看到。问题是,MySQL必须扫描一些东西,所以它也可以是较小的
Hotel
表。我的答案的关键应该是使连接操作的速度比目前更快。我包含的列应该确保这个索引包含执行整个查询所需的所有信息。MySQL必须首先扫描两个表中的一个来启动查询。我建议我们尝试建立一种索引策略,首先扫描较小的表,使用索引处理较大的rooms表?我敢打赌那是令人兴奋的观看。涉及爆炸物吗?还是一台大型起重机?这里有很多关闭/残废的酒店。如果我创建了
Hotel:INDEX(IsClosed,Enabled,HotelId)
在这个例子中顺序是否重要,并说在将来一个
WHERE
子句使用了不同的列order@neildt-按任意顺序将两个标志放在第一位。这将有助于过滤(
WHERE
)。然后将
HotelId
放在最后。优化器将
中的x和y
视为与
中的y和x
相同;也就是说,它双向检查。
索引中的顺序在某些情况下确实很重要,但在您的情况下并不重要,这就是我刚才所说的。在讨论索引时,我尽量做到非常精确——既说必要的,也说足够的。谢谢。如果我创建了索引
Hotel:INDEX(IsClosed,Enabled,HotelId)
,但是在WHERE语句
中也有这个,如果(LENGTH(TRIM(sAuxiliaryIds))>0并且sAuxiliaryIds不为NULL,那么在集合中查找(Hotel.AuxiliaryId,sAuxiliaryIds),1=1)>0
我也应该包括这个列吗?是的,也添加那个索引。(这可能不会产生“巨大”的影响。)