如何优化数据库中的查询 - 基础知识

时间:2010-07-07 03:06:37

标签: sql mysql database optimization query-optimization

似乎关于这个主题的所有问题都非常具体,虽然我重视具体的例子,但我对SQL优化的基础知识很感兴趣。我非常适合在SQL中工作,并且具有硬件/低级软件的背景知识。

我想要的是有形软件的工具,以及查看我定期查看的mysql数据库的方法,并了解join语句的顺序和where语句之间的区别。

我想知道为什么索引有助于确切原因。我想知道具体发生了什么,我想知道如何才能真正看到正在发生的事情。我不需要一个会破坏我SQL的每一步的工具,我只是想能够四处寻找,如果有人不能告诉我要索引的列,我将能够得到一张纸和在一段时间内能够得出答案。

数据库很复杂,但它们并不复杂,并且必须有一些很好的材料来学习基础知识,这样你才能知道如何找到遇到的优化问题的答案,即使可以找到确切的问题。在论坛上回答。

请推荐一些简洁,直观且不怕低级螺母和螺栓的阅读材料。我更喜欢在线免费资源,但是如果一本书的推荐拆除了钉头,我会考虑接受它。

5 个答案:

答案 0 :(得分:7)

假设您正在寻找另一个城市的朋友。一种方法是挨家挨户地询问这是否是您正在寻找的房子。另一种方法是查看地图。

索引是表格的映射。它可以准确地告诉数据库引擎您正在寻找的东西。因此,您可以为您认为必须搜索的每一列编制索引,并省略刚刚从中读取数据的列,并且从不搜索。

良好的技术阅读about indicesabout ORDER BY optimization。如果你想看看究竟发生了什么,你需要EXPLAIN声明。

答案 1 :(得分:6)

你需要查看每个条件和每个连接......条件。两者的工作方式相同。

假设我们写

select name
from customer
where customerid=37;

不知何故,DBMS必须找到customerid = 37的记录或记录。如果没有索引,唯一的方法是读取表中比较customerid到37的每条记录。即使找到一条,也无法知道只有一条,所以它必须继续寻找其他

如果在customerid上创建索引,DBMS可以非常快速地搜索索引。这不是顺序搜索,而是取决于数据库,二进制搜索或其他一些有效的方法。究竟怎么没关系,接受它比顺序要快得多。然后索引将其直接转到相应的记录或记录。此外,如果您指定索引是“唯一”,那么数据库知道只能有一个索引,因此它不会浪费时间寻找秒。 (并且DBMS将阻止您添加秒。)

现在考虑一下这个问题:

select name
from customer
where city='Albany' and state='NY';

现在我们有两个条件。如果您只在其中一个字段上有索引,则DBMS将使用该索引查找记录的子集,然后依次搜索这些记录。例如,如果您有状态索引,DBMS将快速找到NY的第一条记录,然后按顺序搜索以查找city ='Albany',并在它到达NY的最后一条记录时停止查看。

如果您的索引包含两个字段,即“在客户(州,城市)上创建索引”,则DBMS可以立即缩放到正确的记录。

如果您有两个单独的索引,每个字段对应一个,则DBMS将具有适用于决定使用哪个索引的各种规则。同样,具体如何完成取决于您使用的特定DBMS,但基本上它会尝试统计记录总数,不同值的数量和值的分布。然后它将按顺序搜索那些满足其他条件的记录。在这种情况下,DBMS可能会观察到有更多的城市而不是州,因此通过使用城市索引,它可以快速缩放到“奥尔巴尼”记录。然后它将依次搜索这些,检查每个对'NY'的状态。如果您有加州奥尔巴尼的记录,则会跳过这些记录。

每次加入都需要进行某种查找。

说我们写

select customer.name
from transaction
join customer on transaction.customerid=customer.customerid
where transaction.transactiondate='2010-07-04' and customer.type='Q';

现在DBMS必须首先决定要读取哪个表,从那里选择适当的记录,然后在另一个表中找到匹配的记录。

如果您在transaction.transactiondate和customer.customerid上有索引,那么最好的计划可能是找到具有此日期的所有交易,然后为每个交易找到具有匹配的customerid的客户,然后验证客户的类型正确。

如果您在customer.customerid上没有索引,那么DBMS可以快速找到该事务,但是对于每个事务,它必须按顺序搜索customer表以查找匹配的customerid。 (这可能会很慢。)

假设您拥有的唯一索引位于transaction.customerid和customer.type上。然后DBMS可能会使用完全不同的计划。它可能会扫描客户表中所有具有正确类型的客户,然后为每个客户找到该客户的所有交易,并按顺序搜索它们以确定正确的日期。

优化的最重要的关键是找出哪些索引真正有用并创建这些索引。额外的,未使用的索引是数据库的负担,因为它需要工作来维护它们,如果它们从未使用过,这就是浪费精力。

您可以使用EXPLAIN命令告知DBMS将对任何给定查询使用哪些索引。我一直用这个来确定我的查询是否被很好地优化,或者我是否应该创建其他索引。 (有关其输出的说明,请阅读此命令的文档。)

警告:请记住,我说DBMS会记录每个表中的记录数和不同值的数量等。如果数据发生变化,EXPLAIN今天可能会给你一个完全不同于昨天的计划。例如,如果您有一个连接两个表的查询,并且其中一个表非常小而另一个表很大,则它将偏向于首先读取小表,然后在大表中查找匹配的记录。向表中添加记录可以更改哪个更大,从而引导DBMS更改其计划。因此,您应该尝试使用实际数据对数据库执行EXPLAINS。针对每个表中包含5条记录的测试数据库运行的价值远远低于对实时数据库运行的价值。

嗯,还有更多可以说的,但我不想在这里写一本书。

答案 2 :(得分:2)

不要考虑优化数据库。考虑优化查询。

通常,您会以牺牲其他案例为代价来优化一个案例。你只需要决定你感兴趣的案例。

答案 3 :(得分:1)

“我特别感兴趣的是索引将如何影响联接”

作为一个例子,我将以equijoin为例(SELECT FROM A,B WHERE A.x = B.y)。

如果根本没有索引(这在理论上是可能的,但我认为不在SQL中),那么基本上计算连接的唯一方法是获取整个表A并将其分区为x,取整个表y并将其分区为y,然后匹配分区,最后为每对匹配分区计算结果行。除了最小的表之外,所有这些都是昂贵的(或者甚至是由于内存限制而完全不可能)。

如果在A和/或B上确实存在索引,但是没有任何索引具有x resp,则相同。 y作为它的第一个属性。

如果在x上存在索引但在y上(或相反)不存在索引,则会打开另一种可能性:扫描表B,对于每个行选择值y,在索引中查找该值并获取相应的A行计算连接。请注意,如果没有其他进一步的限制(AND z = ...),这仍然不会赢得太多 - 除了在x和y值之间只有很少匹配的情况。

如果在x和y上都存在有序索引(没有排序基于散列的索引),则会打开第三种可能性:对索引本身进行匹配扫描(索引本身可能小于表本身,因此扫描索引本身将花费更短的时间),并且对于匹配的x / y值,计算相应行的连接。

这是基线。 x> y等的连接出现变化。

答案 4 :(得分:1)

我不了解MySql工具,但在MS SqlServer中,您有一个工具可以显示查询将要执行的所有操作以及整个查询将花费多少处理时间。

使用此工具帮助我理解查询优化器如何优化查询,这比我认为任何书都可以提供的帮助更多,因为优化程序的工作通常不容易理解。通过调整查询和可能的下划线数据库,我可以看到每个更改如何影响查询计划。在编写查询时有一些关键点,但对我来说,看起来你已经知道那些在你的情况下如此优化的东西比任何一般规则都要多得多。经过几年的数据库开发,我确实看了几本专门针对SQL Server数据库优化的书,发现很少有用的信息。

快速的谷歌搜索提出了这个问题:http://www.mysql.com/products/enterprise/query.html听起来像是一个类似的工具。

这当然是在查询级别上,数据库级别优化又是一个不同的鱼,但是你正在查看参数,例如你的数据库如何在硬盘驱动器上划分等。至少在SqlServer中你可以选择将表格分成不同的硬盘甚至盘板,这可能会产生很大的影响,因为驱动器和驱动器头可以并行工作。另一个是如何构建查询,以便数据库可以在多个线程和处理器中并行运行它们,但这两个问题再次依赖于数据库引擎甚至是您正在使用的版本。