我已在我的生产服务器中部署了Orchard 1.8。生产服务器是一个具有非常好的规格的专用服务器。然而,每个页面的加载时间大约是3到4秒,这在我们的标准中非常慢。我们有超过一百万的内容项目,我们的印象是Orchard能够处理这样的负载。即使加载空主页也需要花费大量时间。所以我安装了MiniProfiler模块并设法找出瓶颈。它来自此SQL查询
DECLARE @p0 NVARCHAR(4000) = N'Layer'
,@p1 BIT = 1;
SELECT this_.Id AS Id1795_2_
,this_.Number AS Number1795_2_
,this_.Published AS Published1795_2_
,this_.Latest AS Latest1795_2_
,this_.Data AS Data1795_2_
,this_.ContentItemRecord_id AS ContentI6_1795_2_
,contentite1_.Id AS Id1794_0_
,contentite1_.Data AS Data1794_0_
,contentite1_.ContentType_id AS ContentT3_1794_0_
,contenttyp2_.Id AS Id1796_1_
,contenttyp2_.NAME AS Name1796_1_
FROM Orchard_Framework_ContentItemVersionRecord this_
INNER JOIN Orchard_Framework_ContentItemRecord contentite1_ ON this_.ContentItemRecord_id = contentite1_.Id
INNER JOIN Orchard_Framework_ContentTypeRecord contenttyp2_ ON contentite1_.ContentType_id = contenttyp2_.Id
WHERE contenttyp2_.NAME = @p0
AND this_.Published = @p1
我为表Orchard_Framework_ContentTypeRecord
(Name
列ASC)和表Orchard_Framework_ContentItemVersionRecord
(Published
列DESC)添加了索引,但没有改进脚本执行时间。
如何缓解这一瓶颈?这真的是一个交易破坏者,我们花了几个月的时间为客户定制这个网站,要求我们提供一百万个内容项。如果这种情况无法得到纠正,我们即将把整个项目刮掉。请帮忙。
修改
我通过在我的生产服务器和开发机器上部署Orchard 1.8.1的新实例来进行测试。然后用两个完全相同的内容项抽取两个实例。接下来,我在服务器和开发机器上使用SQL Server Management Studio执行上面的SQL脚本。我的生产服务器花了2秒多的时间来检索结果,而我的开发机器花了不到一秒的时间来检索完全相同的结果。
这很奇怪,因为我的生产服务器比我的开发机器强大得多。服务器是一个只运行Orchard实例的专用精简机器,而我的开发机器除运行Orchard实例外,还有20个++浏览器选项卡一起打开的Visual Studio 2013。我的服务器有16GB的RAM,而我的开发机器只有6GB,内存使用率高达96%。当我的开发计算机运行带有SQL Server 2012 Express Edition的Windows 7时,服务器运行带有SQL Server 2014 Entreprise Edition的Windows Server 2012。这两台机器的SQL语句执行计划也不同。我并不擅长阅读执行计划,但如果有必要,我可以在这里包含xml版本执行计划。
更新
最后,我能够确定问题出在SQL Server上。在执行上述脚本时,SQL Server 2014查询优化器与SQL Server 2012相比生成了一个不太理想的执行计划。所以我现在的策略是强制SQL Server 2014(生产服务器)使用SQL Server 2012的执行计划(开发机器)。
这确实是SQL Server而不是Orchard的问题,但由于我已经创建了这个问题,我不妨分享一下我的尝试。 我使用SQL Server 2012中的执行计划以SQL Server 2014中的临时方式查询上述脚本。
DECLARE @p0 NVARCHAR(4000) = N'Layer'
,@p1 BIT = 1;
SELECT this_.Id AS Id1795_2_
,this_.Number AS Number1795_2_
,this_.Published AS Published1795_2_
,this_.Latest AS Latest1795_2_
,this_.Data AS Data1795_2_
,this_.ContentItemRecord_id AS ContentI6_1795_2_
,contentite1_.Id AS Id1794_0_
,contentite1_.Data AS Data1794_0_
,contentite1_.ContentType_id AS ContentT3_1794_0_
,contenttyp2_.Id AS Id1796_1_
,contenttyp2_.NAME AS Name1796_1_
FROM Orchard_Framework_ContentItemVersionRecord this_
INNER JOIN Orchard_Framework_ContentItemRecord contentite1_ ON this_.ContentItemRecord_id = contentite1_.Id
INNER JOIN Orchard_Framework_ContentTypeRecord contenttyp2_ ON contentite1_.ContentType_id = contenttyp2_.Id
WHERE contenttyp2_.NAME = @p0
AND this_.Published = @p1
OPTION (USE PLAN N'<ShowPlanXML ..... (Execution Plan here)')
查询执行时间不到一秒,这是所需的结果。现在,我无法将此执行计划放在Orchard核心源代码中,是吗?因此,我必须在SQL Server 2014中创建计划指南并包含此执行计划。这就是我所做的
EXEC sp_create_plan_guide
@name = N'Published_Layer_Content_Type',
@stmt = N'SELECT this_.Id AS Id1795_2_
,this_.Number AS Number1795_2_
,this_.Published AS Published1795_2_
,this_.Latest AS Latest1795_2_
,this_.Data AS Data1795_2_
,this_.ContentItemRecord_id AS ContentI6_1795_2_
,contentite1_.Id AS Id1794_0_
,contentite1_.Data AS Data1794_0_
,contentite1_.ContentType_id AS ContentT3_1794_0_
,contenttyp2_.Id AS Id1796_1_
,contenttyp2_.NAME AS Name1796_1_
FROM Orchard_Framework_ContentItemVersionRecord this_
INNER JOIN Orchard_Framework_ContentItemRecord contentite1_ ON this_.ContentItemRecord_id = contentite1_.Id
INNER JOIN Orchard_Framework_ContentTypeRecord contenttyp2_ ON contentite1_.ContentType_id = contenttyp2_.Id
WHERE contenttyp2_.NAME = @p0
AND this_.Published = @p1',
@type = N'SQL',
@module_or_batch = NULL,
@params = N'@p0 NVARCHAR(4000), @p1 BIT',
@hints = N'OPTION (USE PLAN N''[Execution Plan here. All single quotes are escaped accordingly]'')'
计划指南已成功创建。我已验证使用SELECT * FROM sys.plan_guides
。但是,每当我执行查询时,都不会使用执行计划。出了什么问题?我是否错误地制定了计划指南?