我们有“个人资料”表,其中包含 60 多个列,例如(Id、fname、lname、性别、profilestate、城市、州、学位...)。
用户在网站上搜索其他人。查询如下:
WITH TempResult as (
select ROW_NUMBER() OVER(ORDER BY @sortColumn DESC) as RowNum, profile.id from Profile
where
(@a is null or a = @a) and
(@b is null or b = @b) and
...(over 60 column)
)
SELECT profile.* FROM TempResult join profile on TempResult.id = profile.id
WHERE
(RowNum >= @FirstRow)
AND
(RowNum <= @LastRow)
sql server默认使用聚集索引来执行查询。但总执行时间超过300。我们测试了另一种解决方案,例如where子句中所有列的多列索引,但总执行时间超过400。 你有什么解决方案可以使总执行时间低于 100. 我们使用sql server 2008。
最佳答案
不幸的是,我认为没有一个纯 SQL 解决方案可以解决您的问题。这里有几个替代方案:
- 动态 SQL - 构建一个仅包含实际提供的值的 WHERE 子句语句的查询。假设平均搜索实际上只填写 2-3 个字段,则可以添加和使用索引。
- 全文搜索 - 进行类似于 Google 关键字搜索的搜索。没有单独的选项。
- Lucene(或其他)- SQL 之外的搜索;不过,这是一个相当重大的变化。
我只记得曾经在系统中实现过另一个选项。创建一个垂直表,其中包含您正在搜索的所有数据,并为其构建查询。使用动态 SQL 最容易做到这一点,但在紧要关头也可以使用表值参数或临时表来完成。
这个想法是制作一个看起来像这样的表格:
- 个人资料 ID
- 属性名称
- 属性值
该表应该在(配置文件 ID,属性名称)上有一个唯一索引(唯一可以使搜索正常工作,索引将使其执行良好)。
在此表中,您将拥有如下数据行:
- (1, '城市', '大急流城')
- (1, '州', 'MI')
- (2, '城市', '底特律')
- (2, '州', 'MI')
那么你的 SQL 将类似于:
SELECT *
FROM Profile
JOIN (
SELECT ProfileID
FROM ProfileAttributes
WHERE (AttributeName = 'city' AND AttributeValue = 'grand rapids')
AND (AttributeName = 'state' AND AttributeValue = 'MI')
GROUP BY ProfileID
HAVING COUNT(*) = 2
) SelectedProfiles ON Profile.ProfileID = SelectedProfiles.ProfileID
... -- Add your paging here
就像我说的,您可以使用具有属性名称/值的临时表:
SELECT *
FROM Profile
JOIN (
SELECT ProfileID
FROM ProfileAttributes
JOIN PassedInAttributeTable ON ProfileAttributes.AttributeName = PassedInAttributeTable.AttributeName
AND ProfileAttributes.AttributeValue = PassedInAttributeTable.AttributeValue
GROUP BY ProfileID
HAVING COUNT(*) = CountOfRowsInPassedInAttributeTable -- calculate or pass in
) SelectedProfiles ON Profile.ProfileID = SelectedProfiles.ProfileID
... -- Add your paging here
我记得,即使在相当复杂的查询上,它最终也表现得非常好(尽管我认为我们只有 12 列左右)。
关于sql server-多列查询优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6387078/