我使用基于具有17个连接(内部和左/右外部)和子查询的复杂查询的视图。所有视图行都在大约5秒内显示。
SELECT * FROM a_view;
其中一个视图列的类型为BIT。当我过滤与1比较的视图行时,查询再次工作大约5秒。
SELECT * FROM a_view WHERE c = 1;
但是当我将这个BIT列与0进行比较时,查询的工作时间约为50秒(慢10倍)。
SELECT * FROM a_view WHERE c = 0;
返回相同结果行的此查询按预期工作大约10秒:
SELECT * FROM a_view
EXCEPT
SELECT * FROM a_view WHERE c = 1;
所以我想知道为什么比较0或'FALSE'需要这么多时间?请问任何想法。
对此BIT字段进行排序很快。其他列过滤也很快。
答案 0 :(得分:1)
SQL Server sql引擎将视图的整个SQL查询放在您在视图上编写的SQL语句中,然后尝试对其进行优化。
这可能会导致c = 0的情况,所用表的统计信息显示与该谓词匹配的行多于c = 1。例如,在c = 1的情况下,包含作为连接中心的c字段的表可能只返回5个匹配行,这导致执行计划与表返回100万行(例如, c = 0的情况。
因此,检查两者的执行计划。同时检查两者的服务器分析器结果,与c = 0一样,可能有比c = 1更多的读取,并且返回的结果比c = 1多得多。返回所有行可能需要一段时间,所以这也可能是查询速度较慢的原因。
答案 1 :(得分:1)
通常,有多种方法可以执行涉及连接的查询。所有现代RDBMS都会搜索不同的连接计划,通过估算每个计划的成本(CPU和磁盘访问时间)来寻找最佳计划。
问题是,查询中的每个额外联接都会将可能计划的数量乘以一个递增的数字,从而导致计划数量双因素(比指数级别增长)增长连接数增加。出于这个原因,数据库必须在某处限制搜索,这意味着对于涉及许多连接的查询,不可避免地会选择次优计划。
作为参考,默认情况下,PostgreSQL在12个连接后停止评估所有可能的计划。 SQL Server肯定会有类似的限制。 17个连接将花费(2 * 13)*(2 * 14)*(2 * 15)*(2 * 16)*(2 * 17)倍的时间进行评估 - 它足以压倒任何有RDBMS的RDBMS曾经存在,或永远。
还有一个事实是,DB会根据粗略统计数据估算成本,例如列中不同值的数量和/或列中10个最常见值的列表。这一切加起来的事实是,随着联接数量的增加,选择最佳(甚至是合理的)联接策略的可能性将向下。
为什么你需要加入17个桌子?你有没有办法简化数据库架构?
答案 2 :(得分:1)
我知道这是一个非常古老的问题,但如果有人还在寻找解决方案,你可以试试这个。我最近遇到了同样的问题,它是一个相对简单的查询,只有3个连接表,其中最大的只有1000多行。不幸的是,我没有权限查看执行计划,所以我不得不即兴发挥。
select * from subquery_x;
非常快,基本上立即完成(返回大约500行),因为它应该
select * from subquery_x where column_x = 1
dtto,非常快,column_x是一个非空位列
select * from subquery_x where column_x = 0
select * from subquery_x where column_x != 1
应该返回大约300行,两者都非常非常慢,实际上花了几分钟!!
简单(但很奇怪)解决方案 - 将where子句中的列转换为tinyint
select * from subquery_x where convert(tinyint,column_x) = 0
我知道这可能会产生一些性能副作用,但它的作用就像魅力一样,将转换后的列值与1进行比较的速度也非常快,所以我就这样说了(它用于提供比较值的报告中)作为参数)
如果有人知道为什么会发生这种情况,请告诉我们,我怀疑这是一个错误,但谁知道,这可能是一个令人讨厌的功能: - )
答案 3 :(得分:0)
与horcic.roman的解决方案类似...我将值或列转换为BIT以大幅提高速度。
myColumn = CAST(1 AS BIT)
CAST(myColumn AS BIT) = 1
显然很奇怪,因为该列是BIT NOT NULL。
答案 4 :(得分:0)
慢:
从bigTable中选择*,其中column = 1
慢
从bigTable中选择*,其中column = cast(1位)
快速:
将@b声明为bit = 1
从bigTable中选择*,其中column = @b