任何人都可以给我任何指针来优化下面的SQL查询。我对SQL不是很了解,但就我所知,以下甚至不能有效地分页数据?
GO
/****** Object: StoredProcedure [dbo].[Nop_ProductLoadAllPaged] Script Date: 04/25/2011 13:26:39 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[Nop_ProductLoadAllPaged]
(
@CategoryID int = 0,
@ManufacturerID int = 0,
@ProductTagID int = 0,
@FeaturedProducts bit = null, --0 featured only , 1 not featured only, null - load all products
@PriceMin money = null,
@PriceMax money = null,
@RelatedToProductID int = 0,
@Keywords nvarchar(MAX),
@SearchDescriptions bit = 0,
@ShowHidden bit = 0,
@PageIndex int = 0,
@PageSize int = 2147483644,
@FilteredSpecs nvarchar(300) = null, --filter by attributes (comma-separated list). e.g. 14,15,16
@LanguageID int = 0,
@OrderBy int = 0, --0 position, 5 - Name, 10 - Price, 15 - creation date
@WarehouseCombinationID int,
@TotalRecords int = null OUTPUT
)
AS
BEGIN
--init
DECLARE @SearchKeywords bit
SET @SearchKeywords = 1
IF (@Keywords IS NULL OR @Keywords = N'')
SET @SearchKeywords = 0
SET @Keywords = isnull(@Keywords, '')
SET @Keywords = '%' + rtrim(ltrim(@Keywords)) + '%'
--filter by attributes
SET @FilteredSpecs = isnull(@FilteredSpecs, '')
CREATE TABLE #FilteredSpecs
(
SpecificationAttributeOptionID int not null
)
INSERT INTO #FilteredSpecs (SpecificationAttributeOptionID)
SELECT CAST(data as int) FROM dbo.[NOP_splitstring_to_table](@FilteredSpecs, ',');
DECLARE @SpecAttributesCount int
SELECT @SpecAttributesCount = COUNT(1) FROM #FilteredSpecs
--paging
DECLARE @PageLowerBound int
DECLARE @PageUpperBound int
DECLARE @RowsToReturn int
SET @RowsToReturn = @PageSize * (@PageIndex + 1)
SET @PageLowerBound = @PageSize * @PageIndex
SET @PageUpperBound = @PageLowerBound + @PageSize + 1
CREATE TABLE #DisplayOrderTmp
(
[ID] int IDENTITY (1, 1) NOT NULL,
[ProductID] int NOT NULL
)
INSERT INTO #DisplayOrderTmp ([ProductID])
SELECT p.ProductID
FROM Nop_Product p with (NOLOCK)
LEFT OUTER JOIN Nop_Product_Category_Mapping pcm with (NOLOCK) ON p.ProductID=pcm.ProductID
LEFT OUTER JOIN Nop_Product_Manufacturer_Mapping pmm with (NOLOCK) ON p.ProductID=pmm.ProductID
LEFT OUTER JOIN Nop_ProductTag_Product_Mapping ptpm with (NOLOCK) ON p.ProductID=ptpm.ProductID
LEFT OUTER JOIN Nop_RelatedProduct rp with (NOLOCK) ON p.ProductID=rp.ProductID2
LEFT OUTER JOIN Nop_ProductVariant pv with (NOLOCK) ON p.ProductID = pv.ProductID
LEFT OUTER JOIN Nop_ProductVariant_Warehouse_Mapping wpv with (NOLOCK) ON pv.ProductVariantID = wpv.ProductVariantID
LEFT OUTER JOIN Nop_ProductVariantLocalized pvl with (NOLOCK) ON pv.ProductVariantID = pvl.ProductVariantID AND pvl.LanguageID = @LanguageID
LEFT OUTER JOIN Nop_ProductLocalized pl with (NOLOCK) ON p.ProductID = pl.ProductID AND pl.LanguageID = @LanguageID
WHERE
(
(
@CategoryID IS NULL OR @CategoryID=0
OR (pcm.CategoryID=@CategoryID AND (@FeaturedProducts IS NULL OR pcm.IsFeaturedProduct=@FeaturedProducts))
)
AND (
@ManufacturerID IS NULL OR @ManufacturerID=0
OR (pmm.ManufacturerID=@ManufacturerID AND (@FeaturedProducts IS NULL OR pmm.IsFeaturedProduct=@FeaturedProducts))
)
AND (
@ProductTagID IS NULL OR @ProductTagID=0
OR ptpm.ProductTagID=@ProductTagID
)
AND (
@RelatedToProductID IS NULL OR @RelatedToProductID=0
OR rp.ProductID1=@RelatedToProductID
)
AND (
@ShowHidden = 1 OR p.Published = 1
)
AND
(
p.Deleted=0 AND wpv.Deleted=0
)
AND
(
@ShowHidden = 1 OR pv.Published = 1
)
AND (
@ShowHidden = 1 OR wpv.Published = 1
)
AND
(
@ShowHidden = 1 OR pv.Deleted = 0
)
AND (
@PriceMin IS NULL OR @PriceMin=0
OR wpv.Price > @PriceMin
)
AND (
@PriceMax IS NULL OR @PriceMax=2147483644 -- max value
OR wpv.Price < @PriceMax
)
AND (
wpv.WarehouseID IN (select WarehouseID from Nop_WarehouseCombination where UserWarehouseCombinationID = @WarehouseCombinationID)
)
AND (
@SearchKeywords = 0 or
(
-- search standard content
patindex(@Keywords, p.name) > 0
or patindex(@Keywords, pv.name) > 0
or patindex(@Keywords, pv.sku) > 0
or (@SearchDescriptions = 1 and patindex(@Keywords, p.ShortDescription) > 0)
or (@SearchDescriptions = 1 and patindex(@Keywords, p.FullDescription) > 0)
or (@SearchDescriptions = 1 and patindex(@Keywords, pv.Description) > 0)
-- search language content
or patindex(@Keywords, pl.name) > 0
or patindex(@Keywords, pvl.name) > 0
or (@SearchDescriptions = 1 and patindex(@Keywords, pl.ShortDescription) > 0)
or (@SearchDescriptions = 1 and patindex(@Keywords, pl.FullDescription) > 0)
or (@SearchDescriptions = 1 and patindex(@Keywords, pvl.Description) > 0)
)
)
AND
(
@ShowHidden = 1
OR
(getutcdate() between isnull(pv.AvailableStartDateTime, '1/1/1900') and isnull(pv.AvailableEndDateTime, '1/1/2999'))
)
AND
(
--filter by specs
@SpecAttributesCount = 0
OR
(
NOT EXISTS(
SELECT 1
FROM #FilteredSpecs [fs]
WHERE [fs].SpecificationAttributeOptionID NOT IN (
SELECT psam.SpecificationAttributeOptionID
FROM dbo.Nop_Product_SpecificationAttribute_Mapping psam
WHERE psam.AllowFiltering = 1 AND psam.ProductID = p.ProductID
)
)
)
)
)
ORDER BY
CASE WHEN @OrderBy = 0 AND @CategoryID IS NOT NULL AND @CategoryID > 0
THEN pcm.DisplayOrder END ASC,
CASE WHEN @OrderBy = 0 AND @ManufacturerID IS NOT NULL AND @ManufacturerID > 0
THEN pmm.DisplayOrder END ASC,
CASE WHEN @OrderBy = 0 AND @RelatedToProductID IS NOT NULL AND @RelatedToProductID > 0
THEN rp.DisplayOrder END ASC,
CASE WHEN @OrderBy = 0
THEN p.[Name] END ASC,
CASE WHEN @OrderBy = 5
THEN dbo.NOP_getnotnullnotempty(pl.[Name],p.[Name]) END ASC,
CASE WHEN @OrderBy = 10
THEN wpv.Price END ASC,
CASE WHEN @OrderBy = 15
THEN wpv.Price END DESC,
CASE WHEN @OrderBy = 20
THEN wpv.Price END DESC,
CASE WHEN @OrderBy = 25
THEN wpv.UnitPrice END ASC
DROP TABLE #FilteredSpecs
CREATE TABLE #PageIndex
(
[IndexID] int IDENTITY (1, 1) NOT NULL,
[ProductID] int NOT NULL
)
INSERT INTO #PageIndex ([ProductID])
SELECT ProductID
FROM #DisplayOrderTmp with (NOLOCK)
GROUP BY ProductID
ORDER BY min([ID])
--total records
SET @TotalRecords = @@rowcount
SET ROWCOUNT @RowsToReturn
DROP TABLE #DisplayOrderTmp
--return
SELECT
p.ProductId,
p.Name,
p.ShortDescription,
p.FullDescription,
p.AdminComment,
p.TemplateId,
p.ShowOnHomePage,
p.MetaKeywords,
p.MetaDescription,
p.MetaTitle,
p.SEName,
p.AllowCustomerReviews,
p.AllowCustomerRatings,
p.RatingSum,
p.TotalRatingVotes,
p.Published,
p.Deleted,
p.CreatedOn,
p.UpdatedOn
FROM
#PageIndex [pi]
INNER JOIN Nop_Product p with (NOLOCK) on p.ProductID = [pi].ProductID
WHERE
[pi].IndexID > @PageLowerBound AND
[pi].IndexID < @PageUpperBound
ORDER BY
IndexID
SET ROWCOUNT 0
DROP TABLE #PageIndex
END
答案 0 :(得分:0)
尽管我讨厌自己这样做,但我认为您可能需要将其分解为一些单独的IF块。
在我看来,你正在根据输入参数加入很多不一定需要的表。如果您关注速度,这是一些不必要的开销。您可以通过创建仅加入所需表的块来简化流程。这有点让你的SP变得有点混乱,我建议你可以创建函数或其他单独的SP来调用你的案例块。
如果你想保持大部分时间,我们需要看到一个实际的执行计划来掌握可能发生的事情。没有它,这只是猜测。
答案 1 :(得分:0)
尝试使用SQL Server的“显示估计执行计划”或“显示实际执行计划”选项,以查看查询的哪些部分占用的时间最多。这样做也可能为您提供其他索引的建议。