- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我们发现这些查询之间存在巨大差异。
查询速度慢
SELECT MIN(col) AS Firstdate, MAX(col) AS Lastdate
FROM table WHERE status = 'OK' AND fk = 4193
表“表”。扫描计数 2,逻辑读取 2458969,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
SQL Server 执行时间:CPU 时间 = 1966 毫秒,运行时间 = 1955 毫秒。
快速查询
SELECT count(*), MIN(col) AS Firstdate, MAX(col) AS Lastdate
FROM table WHERE status = 'OK' AND fk = 4193
表“表”。扫描计数 1,逻辑读取 5803,物理读取 0,预读读取 0,lob 逻辑读取 0,lob 物理读取 0,lob 预读读取 0。
SQL Server 执行时间:CPU 时间 = 0 毫秒,运行时间 = 9 毫秒。
问题
查询之间巨大的性能差异的原因是什么?
更新根据评论中提出的问题进行一点更新:
执行顺序或重复执行不会改变性能。没有使用额外的参数,并且(测试)数据库在执行期间没有执行任何其他操作。
查询速度慢
|--Nested Loops(Inner Join)
|--Stream Aggregate(DEFINE:([Expr1003]=MIN([DBTest].[dbo].[table].[startdate])))
| |--Top(TOP EXPRESSION:((1)))
| |--Nested Loops(Inner Join, OUTER REFERENCES:([DBTest].[dbo].[table].[id], [Expr1008]) WITH ORDERED PREFETCH)
| |--Index Scan(OBJECT:([DBTest].[dbo].[table].[startdate]), ORDERED FORWARD)
| |--Clustered Index Seek(OBJECT:([DBTest].[dbo].[table].[PK_table]), SEEK:([DBTest].[dbo].[table].[id]=[DBTest].[dbo].[table].[id]), WHERE:([DBTest].[dbo].[table].[FK]=(5806) AND [DBTest].[dbo].[table].[status]<>'A') LOOKUP ORDERED FORWARD)
|--Stream Aggregate(DEFINE:([Expr1004]=MAX([DBTest].[dbo].[table].[startdate])))
|--Top(TOP EXPRESSION:((1)))
|--Nested Loops(Inner Join, OUTER REFERENCES:([DBTest].[dbo].[table].[id], [Expr1009]) WITH ORDERED PREFETCH)
|--Index Scan(OBJECT:([DBTest].[dbo].[table].[startdate]), ORDERED BACKWARD)
|--Clustered Index Seek(OBJECT:([DBTest].[dbo].[table].[PK_table]), SEEK:([DBTest].[dbo].[table].[id]=[DBTest].[dbo].[table].[id]), WHERE:([DBTest].[dbo].[table].[FK]=(5806) AND [DBTest].[dbo].[table].[status]<>'A') LOOKUP ORDERED FORWARD)
快速查询
|--Compute Scalar(DEFINE:([Expr1003]=CONVERT_IMPLICIT(int,[Expr1012],0)))
|--Stream Aggregate(DEFINE:([Expr1012]=Count(*), [Expr1004]=MIN([DBTest].[dbo].[table].[startdate]), [Expr1005]=MAX([DBTest].[dbo].[table].[startdate])))
|--Nested Loops(Inner Join, OUTER REFERENCES:([DBTest].[dbo].[table].[id], [Expr1011]) WITH UNORDERED PREFETCH)
|--Index Seek(OBJECT:([DBTest].[dbo].[table].[FK]), SEEK:([DBTest].[dbo].[table].[FK]=(5806)) ORDERED FORWARD)
|--Clustered Index Seek(OBJECT:([DBTest].[dbo].[table].[PK_table]), SEEK:([DBTest].[dbo].[table].[id]=[DBTest].[dbo].[table].[id]), WHERE:([DBTest].[dbo].[table].[status]<'A' OR [DBTest].[dbo].[table].[status]>'A') LOOKUP ORDERED FORWARD)
回答
下面马丁·史密斯给出的答案似乎可以解释这个问题。超短版本是 MS-SQL 查询分析器在慢查询中错误地使用查询计划,从而导致完整的表扫描。
添加 Count(*)、带有 (FORCESCAN) 的查询提示或开始日期、FK 和状态列上的组合索引可修复性能问题。
最佳答案
SQL Server 基数估计器做出各种建模假设,例如
- Independence: Data distributions on different columns are independent unless correlation information is available.
- Uniformity: Within each statistics object histogram step, distinct values are evenly spread and each value has the same frequency.
表中有 810,064 行。
您有疑问
SELECT COUNT(*),
MIN(startdate) AS Firstdate,
MAX(startdate) AS Lastdate
FROM table
WHERE status <> 'A'
AND fk = 4193
1,893 (0.23%) 行满足 fk = 4193
谓词,并且这两个失败 status <> 'A'
因此总共 1,891 个匹配项需要聚合。
您还有两个索引,它们都不覆盖整个查询。
为了快速查询,它使用 fk
上的索引直接查找 fk = 4193
所在的行那么需要做 1,893 key lookups查找聚集索引中的每一行以检查 status
谓词并检索startdate
用于聚合。
当您删除COUNT(*)
时来自SELECT
list SQL Server 不再必须处理每个符合条件的行。因此,它考虑了另一种选择。
您的索引位于 startdate
因此它可以从头开始扫描,对基表进行键查找,一旦找到第一个匹配行就停止,因为它找到了 MIN(startdate)
,类似地MAX
可以通过从索引的另一端开始并向后进行另一次扫描来找到。
SQL Server 估计每次扫描最终都会处理 590 行,然后才能找到与谓词匹配的行。总查找次数为 1,180 次,而查找次数为 1,893 次,因此它选择了此计划。
590这个数字就是table_size / estimated_number_of_rows_that_match
。即基数估计器假设匹配的行将均匀分布在整个表中。
不幸的是,满足谓词的 1,891 行不是随机分布于 startdate
。事实上,它们都在索引末尾压缩为一个 8,205 行段,这意味着扫描将到达 MIN(startdate)
最终在停止之前进行了 801,859 个键查找。
这可以在下面复制。
CREATE TABLE T
(
id int identity(1,1) primary key,
startdate datetime,
fk int,
[status] char(1),
Filler char(2000)
)
CREATE NONCLUSTERED INDEX ix ON T(startdate)
INSERT INTO T
SELECT TOP 810064 Getdate() - 1,
4192,
'B',
''
FROM sys.all_columns c1,
sys.all_columns c2
UPDATE T
SET fk = 4193, startdate = GETDATE()
WHERE id BETWEEN 801859 and 803748 or id = 810064
UPDATE T
SET startdate = GETDATE() + 1
WHERE id > 810064
/*Both queries give the same plan.
UPDATE STATISTICS T WITH FULLSCAN
makes no difference*/
SELECT MIN(startdate) AS Firstdate,
MAX(startdate) AS Lastdate
FROM T
WHERE status <> 'A' AND fk = 4192
SELECT MIN(startdate) AS Firstdate,
MAX(startdate) AS Lastdate
FROM T
WHERE status <> 'A' AND fk = 4193
您可以考虑使用查询提示来强制计划使用 fk
上的索引而不是startdate
或者添加执行计划中突出显示的建议缺失索引 (fk,status) INCLUDE (startdate)
以避免这个问题。
关于SQL 为什么 SELECT COUNT(*) , MIN(col), MAX(col) 比 SELECT MIN(col), MAX(col) 更快,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7481818/
我有一个照片库的标准循环,我正在使用 twitter-bootstrap col-xs-12 col-sm-6 col-md-4 col-lg-3 这让我在桌面上看到 4 张图片,在移动设备上缩小到单
我有一个关于 bootstrap 3.0 类顺序的问题,现在如果我在从 sm 到 lg 的地方写下以下内容:- 如果我将类(class)顺序从 lg 更改为 sm,会有什么不同吗:- 或者顺序无关
如果类中没有指定col-lg和col-md,那么col-sm是否适用于所有大屏? 最佳答案 是的。 来自 bootstrap , Grid classes apply to devices with
我有一个概念,希望你能帮助澄清: 以下三种引用 PySpark 数据框中列的方式有什么区别。我知道不同的情况需要不同的形式,但不知道为什么。 df.col :例如F.count(df.col) df[
我们的代码是用C写的,DB是Informix。我们正在对 ESQL 程序进行一些代码优化,发现以下查询: UPDATE [TABLE] SET [PRIMARY KEY COLUMN] = [NEW
我的网站需要 3*3 的响应式服务框。但对齐方式不正确。第一行中的每个框在第二行中都不同,最后一个框正在移动到第四行。因此需要 3*3 框类型的代码。
我们发现这些查询之间存在巨大差异。 查询速度慢 SELECT MIN(col) AS Firstdate, MAX(col) AS Lastdate FROM table WHERE status =
如何在 gnuplot 中执行此操作: plot "test.csv" using 1:2 if value_in_column_3 == 80.0 它应该只选择第 3 列 == 80.0 的行并忽略
不确定从哪里开始 - 不确定问题是我在愚弄查询优化器,还是涉及空值时索引工作方式的固有问题。 我遵循的一个编码惯例是像这样编写存储过程: declare procedure SomeProc @I
两者之间有什么区别吗: CONCAT_WS('', 列)='' 和 列为空或列=0 *(以及可选的“OR column="”')* 其中一个更好/更快吗......? SELECT my_fields
我有一个像这样的数据框: ColA ColB ColC "lorem ipsum" ["lorem", "foo"
我在编写查询时遇到问题。假设我有一个包含汽车制造商和型号的表格,但我想删除所有与型号列表无关的行,我已经写了这个... DELETE FROM `cars` WHERE `make` != 'Ford
而不是使用 我可以这样做吗, ? 即MyCOLUMS = col-xs-1 col-sm-2 col-md-3 col-lg-4 . 如果可能,请解释如何实现?如果此方法错误,请解释错误原因。 最佳答
我必须在机器学习之前做一些数据清理,我的数据框如下所示: +-------+--------+---------+--------+-------+| userid|artistid|playcoun
在我的左边col我有一个 在我的右边col我有一些文字。我要左边col与右侧高度相同col .然后我想要 填补左边col .看起来很简单,但我做不到。这是我当前的代码:
我很好奇替换是否正确 ... ... 与 ... ... 用javascript? 我所需要的只是隐藏第二个 div 并正确地通过 javascript 显示第一个 div 的 100%。实际完成的操
我尝试了很多不同的解决方案:将类中心 block 添加到“行”,将“行”包装在 .我只想有 4 个 imges,居中,但它们被移到了左边。请帮助我,我的错误是什么?谢谢。
假设我有 COUNTRY |邮政编码 列。会有很多重复项,但大多数情况下,一些 COUNTRY 值将丢失,而 POSTAL CODE 将出现。如何在 POSTAL CODE 匹配的其他行中用 COUN
Twitter Bootstrap 中的 col-lg-* 、col-md-* 和 col-sm-* 有什么区别? 最佳答案 2020 年更新... Bootstrap 5 在 Bootstrap 5
问题:IE8 仅考虑我的带有 col-x 类的网格布局。我发现了一个相关/类似的问题IE8 issue with Twitter Bootstrap 3 wrt Respond.js 和 htm5sh
我是一名优秀的程序员,十分优秀!