从包含大量数据的查询中获取行数的优化方法

2021-09-10 00:00:00 sql tsql sql-server rowcount

我正在使用下面的查询返回用于分页的行数,它工作正常但需要很长时间才能返回,因为所有表都有数百万条记录.目前返回 rowcount 需要 7 秒,任何人都可以帮助我快速返回它.

i am using the below query to return rowcount for paging, it works fine but take very long to return, because all of the table have millions of records. currently its taking 7 sec to return rowcount, can anyone help me in this to return it fast.

我也尝试过同样的查询,#table 和 @table 都很慢.查询是

i have also tried same query with #table and @table both are slow. query is

WITH cte_rowcount 
     AS (SELECT p.policyid 
         FROM   resident (nolock) r 
                INNER JOIN resident_policy (nolock) rp 
                        ON r.residentid = rp.residentid 
                INNER JOIN policy (nolock) p 
                        ON p.policyid = rp.policyid 
                --INNER JOIN PolicySource (NOLOCK) psourse ON p.PolicySourceID = psourse.PolicySourceId 
                INNER JOIN policy_locations (nolock) pl 
                        ON pl.policyid = p.policyid 
                INNER JOIN location (nolock) l 
                        ON pl.locationid = l.locationid 
                --INNER JOIN Policy_Status (NOLOCK) ps ON ps.PolicyStatusId = p.PolicyStatusId 
                INNER JOIN property (nolock) pr 
                        ON pr.propertyid = l.propertyid 
         --INNER JOIN dbo.States (NOLOCK) s ON s.StateId = pr.StateId 
         WHERE  r.primary_resident = 0x1 
                AND ( ( @ResidentFirstName IS NULL ) 
                       OR R.firstname LIKE @ResidentFirstName + '%' ) 
                AND ( ( @ResidentLastName IS NULL ) 
                       OR R.firstname LIKE @ResidentLastName + '%' ) 
                AND ( @PropertyAddress IS NULL 
                       OR pr.address LIKE @PropertyAddress + '%' ) 
                AND ( @Policynumber IS NULL 
                       OR p.policynumber LIKE @Policynumber + '%' ) 
                AND ( @LocationAddress IS NULL 
                       OR l.address2 LIKE @LocationAddress + '%' ) 
                AND ( @City IS NULL 
                       OR pr.city LIKE @City + '%' ) 
                AND ( @ZipCode IS NULL 
                       OR pr.zipcode = @ZipCode ) 
                AND ( @StateId IS NULL 
                       OR pr.stateid = @StateId ) 
                AND ( @PolicyStatusId IS NULL 
                       OR p.policystatusid = @PolicyStatusId )) 
SELECT @rowcount = Count(*) 
FROM   cte_rowcount 

推荐答案

我会说查看索引,但它可能不会有太大帮助,因为 a) 您可能已经这样做了,并且 b) 您可以这种查询没有搜索,只有扫描.

I'd say to look at the indexes, but it probably won't help much, because a) you probably did it already, and b) you can get no seeks with this kind of a query, only scans.

这个想法是摆脱这些 OR 并让优化器产生一个合理的计划.

The idea is to get rid of these ORs and allow the optimizer to produce a sound plan.

有两种选择.

不知道哪个版本的 SQL Server 有问题,但如果它是 SQL 2008 SP1 CU5 (10.0.2746) 或更高版本,或者 SQL 2008 R2 CU1 (10.50.1702) 或更高版本,或者任何更新的版本,将 option (recompile) 添加到查询中.这应该会产生更好的计划,在相关索引上使用搜索.

Don't know which version of SQL Server is in question, but if it's SQL 2008 SP1 CU5 (10.0.2746) or later, or SQL 2008 R2 CU1 (10.50.1702) or later, or anything newer than that, add an option (recompile) to the query. This should produce much better plan, using seeks on relevant indexes.

然而,这会给每次执行增加一些重新编译的开销,所以也许第二个选项更好.

This will, however, add some recompile overhead to every execution, so maybe the second option is better.

您可以将查询重写为动态查询,并在优化器甚至看到查询之前消除 NULL 参数.我试图重写您的查询,没有您的数据,因此无法对其进行测试,并且其中可能存在一些错误,但您还是会明白我的意图.我不得不猜测数据类型.(顺便说一句,SELECT p.policyid 是否有特定原因?)

You can rewite the query into dynamic one, and elliminate the NULL parameters before optimizer even see the query. I tried to rewrite your query, don't have your data so can't test it, and there may be some errors in it, but you'll get my intention nevertheless. And I had to guess the datatypes. (BTW, is there a specific reason for SELECT p.policyid?)

这是:

declare @qry nvarchar(4000), @prms nvarchar(4000);
set @qry = N'
SELECT count(*)
         FROM   resident (nolock) r 
                INNER JOIN resident_policy (nolock) rp 
                        ON r.residentid = rp.residentid 
                INNER JOIN policy (nolock) p 
                        ON p.policyid = rp.policyid 
                INNER JOIN policy_locations (nolock) pl 
                        ON pl.policyid = p.policyid 
                INNER JOIN location (nolock) l 
                        ON pl.locationid = l.locationid 
                INNER JOIN property (nolock) pr 
                        ON pr.propertyid = l.propertyid 
         WHERE  r.primary_resident = 0x1 '
if @ResidentFirstName IS NOT NULL
    set @qry = @qry + ' AND R.firstname LIKE @ResidentFirstName + ''%'''  
if @ResidentLastName IS NOT NULL 
    set @qry = @qry + ' AND R.firstname LIKE @ResidentLastName + ''%'''
if @PropertyAddress IS NOT NULL 
    set @qry = @qry + ' AND pr.address LIKE @PropertyAddress + ''%''' 
if @Policynumber IS NOT NULL 
    set @qry = @qry + ' AND p.policynumber LIKE @Policynumber + ''%''' 
if @LocationAddress IS NOT NULL 
    set @qry = @qry + ' AND l.address2 LIKE @LocationAddress + ''%''' 
if @City IS NOT NULL 
    set @qry = @qry + ' AND pr.city LIKE @City + ''%''' 
if @ZipCode IS NOT NULL 
    set @qry = @qry + ' AND pr.zipcode = @ZipCode'
if @StateId IS NOT NULL 
    set @qry = @qry + ' AND pr.stateid = @StateId'
if @PolicyStatusId IS NOT NULL 
    set @qry = @qry + ' AND p.policystatusid = @PolicyStatusId'


set @prms = N'@PolicyStatusId int, @StateId int, @ZipCode int,
@City varchar(50), @LocationAddress varchar(50), @Policynumber varchar(50), 
@PropertyAddress varchar(50), @ResidentLastName varchar(50), @ResidentFirstName varchar(50)'

exec sp_executesql 
@qry, 
@prms,
@PolicyStatusId = @PolicyStatusId, @StateId = @StateId, @ZipCode = @ZipCode,
@City = @City, @LocationAddress = @LocationAddress, 
@Policynumber = @Policynumber, @PropertyAddress = @PropertyAddress, 
@ResidentLastName = @ResidentLastName, @ResidentFirstName = @ResidentFirstName

如果您检查执行计划,您将看到索引查找,前提是您在 WHERE 和 JOIN 列上有非聚集索引.

If you chect the execution plan you'll see the index seeks, provided you have nonclustered indexes on WHERE and JOIN columns.

此外,计划将被缓存,每个参数组合一个.

Moreover, the plan will be cached, one for each combination of parameters.

相关文章