SQL服务器并发访问

时间:2010-01-11 16:56:07

标签: sql-server performance

当sql server正在接收两个查询(SELECT * From the_Same_Table)时,如果你有一个服务器有多个处理器,那么sql server是否可以同时检索数据?

我试图了解如果在.01秒内完成的廉价select语句和1000个用户同时完全运行相同查询会发生什么。我认为如果服务器有四个处理器会发生什么情况,那么SQL服务器将在.01秒内服务前四个,并在0.02秒内为下一个四个用户提供额外服务。

这甚至接近实际发生的事情吗?

我想我会尝试使用某种代码和记录器来测试它,或者可能有可靠的测试工具来做这件事。

谢谢

3 个答案:

答案 0 :(得分:18)

进入SQL Server的每个批处理(请求)都会创建一个任务。任务计划执行并由工作人员接收。工人与线程非常相似。任务与工作人员保持一致,直到完成,然后它释放工人以获取另一个任务。系统中的工作人员数量有限,由sp_configure 'max worker threads'配置。至少有256名工人,其中大约35名是系统。工作人员需要运行调度程序,每个CPU核心都有一个调度程序。工人们合作共享调度程序。

某些任务产生子任务,如并行查询。这些任务也排队等待执行,需要工人完成。产生子任务的任务无法完成,直到它产生的所有任务都完成。

还有一些用户操作驱动的系统任务,如登录握手。当客户端打开新连接时,握手和登录身份验证/授权由任务完成,这需要工作人员。

当1000个请求到达服务器时,将创建1000个任务并排队等待执行。自由工作者接受任务并开始执行它们。当他们完成一项任务时,他们会接受下一个任务,直到完成1000个请求创建的所有任务。

显示正在发生的事情的DMV是:

SQL Server Batch or Task SchedulingSlava's blog中介绍了这些详细信息。

此外,一旦任务执行,将编译请求。编译将首先在内存中查找请求文本,并搜索具有相同计划的请求的现有编译计划。您可以阅读我对Dynamically created SQL vs Parameters in SQL Server的回复,以便更详细地了解这种情况。另请参阅Execution Plan Caching and Reuse。创建计划后,它将启动执行。像SELECT ... FROM table之类的查询将创建一个简单的计划,该计划只有几个运算符,基本上可以获取每一行并将其放入TDS流中返回给客户端。查询计划是运算符树,并且始终通过在循环中询问树的根来执行查询,直到根返回EOF。树下的查询运算符越来越具体,直到底层运算符将是对所选访问路径(优化器为满足查询而选择的索引或堆)的物理访问。见SQL Statement Processing。索引访问将始终从缓冲池请求数据,而不是从磁盘请求。当缓冲池没有缓存请求的页面时,页面上会放置一个PAGEIOLATCH,并且会向IO子系统提交读取页面的请求。对同一页面的后续请求将等待此IO完成,并且一旦页面在缓冲池中,所有其他需要此页面的查询将从缓冲池中获取。当缓冲池需要空闲页面时,未使用的页面被驱逐,但如果系统有足够的RAM,则一旦加载,页面将永远不会被驱逐。索引和堆扫描操作将请求预读,预计将请求页面链接链中当前页面之前的页面。预读受到索引contiguos片段的限制,这是当索引碎片出现时,因为它减少了预读请求的大小,请参阅Understanding Pages and Extents

查询执行的另一个方面是行的逻辑锁定。为了稳定性,读取可以在其读取的行上放置行锁或范围锁(取决于隔离模型),以防止在查询遍历扫描时进行concurent更新。在SNAPSHOT隔离级别下,查询根本不会请求锁定,而是使用版本标记来提供从版本存储请求的数据(请参阅SQL Server 2005 Row Versioning-Based Transaction Isolation)。在READ UNCOMMITED隔离下(或使用nolock提示时),查询不会请求对其读取的行进行锁定,但如果发生了concurent更新,则读取不一致(读取未读取的行,读取相同的行两次,或者现有行可能根本没有读过。)

答案 1 :(得分:2)

不,您对顺序处理的假设不正确,这个主题变得非常复杂和深刻 - 试图让我所知道的简单:

每个查询都分配了一个线程,并且调度程序使用协作调度,而不是先发制人,因此每个线程可以在被调度程序强制执行之前放弃时间分配(量子)。 每个查询都必须从缓冲池请求数据,这可能意味着等待IO /网络等,因此它们将达到等待状态并产生处理时间的量子。

当进程不再等待资源时,可以重新输入可用于处理的线程列表,然后将获得另一个量的时间来处理请求。

实际上您的请求是并行运行的,但您无法确定性地预测请求的完成顺序。

为了真正深入了解这一点,我认为SQL 2008 Internals书籍形式Kalen Delaney(Adam Mechanic,Kimberley Tripp,Paul Randal)是一个很好的起点,或Ken Henderson的旧SQL Server 2000架构书,这也是非常低的水平。

我必须回顾课程笔记,以便记住确切的过程 - 它得到了问题 - '因为你不能直接影响这个,你为什么要问?'

答案 2 :(得分:1)

Sql server针对并发多次读取进行了优化。只有在尝试访问的同一个表上发生了大量更新操作时,才会遇到死锁。但是,如果是这种情况,您可以使用nolock甚至将事务隔离级别设置为READ UNCOMMITTED

现在关于你的线程问题。 SQL Server使用称为纤维的东西,就像子线程一样。因此,您不一定会看到在多处理器环境中期望看到的相同处理器线程扩展。虽然SQL服务器可以访问一定数量的线程,但也可以使用最大数量的光纤。这就是为什么你可以让1000个客户端在小盒子上同时访问同一个服务器的原因。

如果你真的想进入线程/光纤调度,你需要找到一个好的SQL Server,因为它很复杂,所以真正得到了它。

只是意识到sql server已针对此进行了优化,您无需以任何方式对其进行单元测试,因为已经使用您可能无法重新创建的工具进行了验证。