![]() |
1
6
您必须查找每个where条件和每个join…条件。两个工作原理相同。 假设我们写信
不知为何,DBMS必须找到一个或多个customerid=37的记录。如果没有索引,那么执行此操作的唯一方法是读取表中的每个记录,将customerid与37进行比较。即使找到了一个,它也无法知道只有一个,所以它必须不断地寻找其他人。 如果在customerid上创建一个索引,DBMS可以很快地搜索该索引。这不是顺序搜索,但取决于数据库、二进制搜索或其他有效方法。确切地说,有什么不重要的,接受它比顺序要快得多。然后,索引将其直接带到适当的一个或多个记录中。此外,如果您指定索引是“唯一的”,那么数据库知道只能有一个索引,因此它不会浪费时间寻找第二个索引。(DBMS将阻止您添加一秒钟。) 现在考虑这个查询:
现在我们有两个条件。如果只有一个字段上有索引,DBMS将使用该索引查找记录的一个子集,然后按顺序搜索这些记录。例如,如果您有状态索引,DBMS将快速找到NY的第一条记录,然后按顺序搜索查找city='albany',当它到达NY的最后一条记录时停止查找。 如果您有一个包含这两个字段的索引,即“在客户(州、市)上创建索引”,那么DBMS可以立即缩放到正确的记录。 如果您有两个单独的索引,每个字段一个,那么DBMS将应用各种规则来决定要使用哪个索引。同样,如何做到这一点取决于您所使用的特定DBMS,但基本上,它试图保持对记录总数、不同值的数量和值分布的统计。然后它将按顺序搜索这些记录以查找满足其他条件的记录。在这种情况下,DBMS可能会观察到有比州更多的城市,因此通过使用城市索引,它可以快速地缩放到“奥尔巴尼”记录。然后它将按顺序搜索这些内容,并对照“ny”检查每个内容的状态。如果你有加利福尼亚州奥尔巴尼的记录,这些将被跳过。 每个连接都需要某种查找。 说我们写
现在,DBMS必须决定首先读取哪个表,从中选择适当的记录,然后在另一个表中找到匹配的记录。 如果您对transaction.transactionDate和customer.customerID有索引,那么最好的计划可能是查找所有具有此日期的交易,然后为每个交易查找具有匹配customerID的客户,然后验证该客户的类型是否正确。 如果在customer.customerid上没有索引,那么DBMS可以快速找到事务,但是对于每个事务,它必须按顺序搜索customer表以查找匹配的customerid。(这可能非常慢。) 假设您拥有的唯一索引是transaction.customerid和customer.type。那么DBMS可能会使用完全不同的计划。它可能会扫描customer表中所有具有正确类型的客户,然后针对每个客户查找此客户的所有交易,并按顺序搜索这些交易以查找正确的日期。 优化的最重要的关键是找出哪些索引真正有帮助,并创建这些索引。另外,未使用的索引对数据库来说是一个负担,因为维护它们需要工作,如果它们从未被使用过,这是浪费的工作。 您可以使用explain命令来告诉DBMS将用于任何给定查询的索引。我一直使用这个方法来确定我的查询是否得到了很好的优化,或者是否应该创建额外的索引。(有关该命令输出的说明,请阅读该命令的文档。) 注意:请记住,我说过DBMS会对每个表中的记录数量和不同值的数量等进行统计。如果数据发生变化,“解释”可能会给你一个与昨天完全不同的计划。例如,如果您有一个连接两个表的查询,其中一个表非常小,而另一个表很大,那么它将倾向于先读取小表,然后在大表中查找匹配的记录。向表中添加记录可能会改变较大的值,从而导致DBMS更改其计划。因此,您应该尝试对具有实际数据的数据库进行解释。在每个表中有5条记录的测试数据库上运行比在活动数据库上运行要小得多。 嗯,还有很多话可以说,但我不想在这里写一本书。 |
![]() |
2
7
假设你在另一个城市找朋友。一种方法是挨家挨户地问这是否是你要找的房子。另一种方法是看地图。 索引是到表的映射。它可以准确地告诉数据库引擎你要找的东西在哪里。因此,您为您认为必须搜索的每一列编制索引,并删除您刚刚从中读取数据的列,而不搜索这些列。
良好的技术阅读能力
about indices
和
about
|
![]() |
3
2
不要考虑优化数据库。考虑优化查询。 通常,您会以牺牲其他案例为代价优化一个案例。你只需决定你感兴趣的案件。 |
![]() |
4
1
“我对索引将如何影响联接特别感兴趣。” 作为一个例子,我将以equijoin为例(从a,b中选择,其中a.x=b.y)。 如果根本没有索引(理论上是可能的,但我认为不是在SQL中),那么基本上计算联接的唯一方法是取整个表A并将其分区到X上,取整个表Y并将其分区到Y上,然后匹配分区,最后对每对匹配分区计算结果行。对于除了最小的表以外的所有表来说,这都是昂贵的(甚至完全不可能,因为内存限制)。 如果A和/或B上确实存在索引,但没有任何索引具有x resp,那么情况也是一样的。Y是它的第一个属性。 如果X上确实存在索引,但Y上不存在索引(或相反),则会打开另一种可能性:扫描表B,对于每行选择值Y,在索引中查找该值并获取相应的A行以计算联接。请注意,如果没有其他限制(和z=……)的话,这仍然不会给您带来多少好处-除非在x和y值之间只有很少的匹配。 如果X和Y上都存在有序索引(基于哈希的索引没有排序),那么第三种可能性就出现了:对索引本身进行匹配扫描(索引本身可能比表本身小,因此扫描索引本身需要更短的时间),对于匹配的X/Y值,计算相应的行。 这就是底线。X>Y等连接出现变化。 |
![]() |
5
1
我不知道MySQL工具,但在MS SQLServer中,有一个工具可以显示查询所需的所有操作,以及整个查询的处理时间。 使用这个工具帮助我了解查询优化器是如何优化查询的,这比我认为任何一本书都能帮助的多,因为优化器所做的通常不容易理解。通过调整查询和可能的下划线数据库,我可以看到每个更改是如何影响查询计划的。在编写查询时有一些关键点,但对我来说,似乎您已经了解了这些关键点,因此在您的案例中,优化比任何一般规则都更重要。经过几年的数据库开发,我确实看了几本专门针对SQL Server上数据库优化的书,发现很少有用的信息。 快速谷歌发现了这个: http://www.mysql.com/products/enterprise/query.html 这听起来像是一个类似的工具。 当然,在查询级别上,数据库级别的优化又是另一回事,但在这里,您将看到一些参数,例如数据库在硬盘上的划分方式等。至少在sqlserver中,您可以选择将表划分到不同的HDD,甚至磁盘,这会产生很大的影响,因为驱动器驱动头可以并联工作。另一个问题是如何构建查询,以便数据库可以并行地在多个线程和处理器中运行它们,但这两个问题再次取决于数据库引擎,甚至是您使用的版本。 |
![]() |
giantjenga · 优化整数向量到二进制向量的转换 8 月前 |
![]() |
Daniel Lobo · 使用约束进行优化 9 月前 |
![]() |
Sergio · python中大量数字的乘法 1 年前 |
![]() |
Sergey Dev · 临时表与表变量 1 年前 |
![]() |
John · 减少C中的内存消耗++ 1 年前 |