我正在优化我的表并专门添加索引以减少读取/查询。标识为具有高读取的表之一是Users表。但是,在ID
上过滤的列已经是索引。为什么通过索引执行如此多的读取来过滤简单查询?
该表有大约200行。大约一半的时间是针对它运行查询(根据SQL Server Profiler),它执行112次读取需要16ms。我意识到这些数字本身都不高,但由于这是一个非常常见的查询,应该在> 1ms内执行1次读取,我很想知道如何进一步调试。
CREATE TABLE [dbo].[Users]
(
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](15) NULL,
[Password] [varchar](128) NULL,
[Code] [varchar](20) NULL,
[ResetCode] [varchar](32) NULL,
[ResetTime] [datetime] NULL,
[LastLogin] [datetime] NULL,
[LastIP] [varchar](50) NULL,
[UserSettings] [varchar](max) NULL,
[LastName] [varchar](30) NULL,
[FirstName] [varchar](30) NULL,
[Middle] [varchar](30) NULL,
[Address1] [varchar](50) NULL,
[Address2] [varchar](50) NULL,
[City] [varchar](50) NULL,
[State] [varchar](4) NULL,
[Zip] [varchar](10) NULL,
[Email] [varchar](80) NULL,
[Flag] [tinyint] NULL,
[Inactive] [tinyint] NULL,
CONSTRAINT [PK_Users]
PRIMARY KEY CLUSTERED ([ID] ASC)
)
SELECT
ID AS id,
Name AS username,
FirstName AS first_name,
LastName AS last_name,
Email AS email,
Flag AS flag
FROM Users
WHERE ID = 180
这是我手动执行它所以不确定它是否与从php web app发送时使用的相同。 https://www.brentozar.com/pastetheplan/?id=HkCx99Xnf
答案 0 :(得分:0)
好吧,它需要读取所有列,因为你没有包含select语句中所有列的覆盖索引。
您需要创建一个使用ID列的索引,并包含您需要的列。
请注意,并非所有版本的SQL Server都有覆盖索引, 语法是:
create index [IX_SingeUsers] on [dbo].[Users] (ID)
include ([Name],[FirstName],[LastName],[Email],[Flag])
对于是,请随意为索引命名,而不是在我的示例中 IX_SingeUsers
或者,您可以创建具有覆盖索引的视图,并针对该视图进行选择。带索引的视图是"表"并作为SQL Server内部的表存储和维护。然后,您只需拥有您正在寻找的数据并且速度非常快,并且在覆盖索引的更多许可模型中最好。
覆盖索引绑定到表架构,如果您想更新表,首先需要删除视图,然后在完成表更改后重新创建它。
索引视图记录为here,更改版本以获取您部署的版本的正确信息。
更新: 请注意,这不会读取所有行,它只会读取落在索引统计信息中的那些扩展区(希望您更新它们)的聚集索引和所提到的覆盖索引,这可能只有1个扩展并且只有那些索引中的列也可能适合这8个数据页。它不需要转到表,因为索引提取将提供查询需要返回的所有数据。
请记住,SQL会在数据库中锁定此数据,以确保没有数据损坏。如果您有许多用户且没有分区,则可能会发生表锁定。与磁盘读取相比,这对性能的影响要大得多。查看磁盘队列长度以查看是否存在磁盘延迟问题。
快乐编码
沃尔特