简体   繁体   English

EF生成的查询需要太多时间才能执行

[英]Query generated by EF takes too much time to execute

I have a very simple query which is generated by Entity-Framework, Sometimes when I try to run this query It almost takes more than 30 seconds to be executed, and I got time out Exception . 我有一个由实体框架生成一个非常简单的查询, 有时,当我尝试运行此查询它几乎需要被执行超过30秒,我得到超时Exception

SELECT TOP (10) 
[Extent1].[LinkID] AS [LinkID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Url] AS [Url], 
[Extent1].[Description] AS [Description], 
[Extent1].[SentDate] AS [SentDate], 
[Extent1].[VisitCount] AS [VisitCount], 
[Extent1].[RssSourceId] AS [RssSourceId], 
[Extent1].[ReviewStatus] AS [ReviewStatus], 
[Extent1].[UserAccountId] AS [UserAccountId], 
[Extent1].[CreationDate] AS [CreationDate]
FROM ( SELECT [Extent1].[LinkID] AS [LinkID], [Extent1].[Title] AS [Title], [Extent1].[Url] AS [Url], [Extent1].[Description] AS [Description], [Extent1].[SentDate] AS [SentDate], [Extent1].[VisitCount] AS [VisitCount], [Extent1].[RssSourceId] AS [RssSourceId], [Extent1].[ReviewStatus] AS [ReviewStatus], [Extent1].[UserAccountId] AS [UserAccountId], [Extent1].[CreationDate] AS [CreationDate], row_number() OVER (ORDER BY [Extent1].[SentDate] DESC) AS [row_number]
    FROM [dbo].[Links] AS [Extent1]
)  AS [Extent1]
WHERE [Extent1].[row_number] > 0
ORDER BY [Extent1].[SentDate] DESC

And the code which is generating the Query is: 生成查询的代码是:

public async Task<IQueryable<TEntity>> GetAsync(Expression<Func<TEntity, bool>> filter = null,
    Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> orderBy = null)
{
    return await Task.Run(() =>
    {
        IQueryable<TEntity> query = _dbSet;
        if (filter != null)
        {
            query = query.Where(filter);
        }

        if (orderBy != null)
        {
            query = orderBy(query);
        }

        return query;
    });
}

Note that when I remove inner Select statement and Where clause and change it to following, Query executes fine in a less than a second. 请注意,当我删除内部Select语句和Where子句并将其更改为以下时,Query会在不到一秒的时间内执行。

SELECT TOP (10) 
[Extent1].[LinkID] AS [LinkID], 
[Extent1].[Title] AS [Title], 
.
.
.
FROM [dbo].[Links] AS [Extent1]
ORDER BY [Extent1].[SentDate] DESC

Any advice will be helpful. 任何建议都会有所帮助。

UPDATE: 更新:

Here is the usage of Above code: 以下是上述代码的用法:

var dbLinks = await _uow.LinkRespository.GetAsync(filter, orderBy);
var pagedLinks = new PagedList<Link>(dbLinks, pageNumber, PAGE_SIZE);
var vmLinks = Mapper.Map<IPagedList<LinkViewItemViewModel>>(pagedLinks);

And filter: 并过滤:

var result = await GetLinks(null, pageNo, a => a.OrderByDescending(x => x.SentDate));

It never occurred to me that you simply didn't have an index. 我从未想过你根本就没有索引。 Lesson learnt - always check the basics before digging further. 获得的经验 - 在进一步挖掘之前,请务必检查基础知识。


If you don't need pagination, then the query can be simplified to 如果您不需要分页,则可以将查询简化为

SELECT TOP (10) 
    [Extent1].[LinkID] AS [LinkID], 
    [Extent1].[Title] AS [Title], 
    ...
FROM [dbo].[Links] AS [Extent1]
ORDER BY [Extent1].[SentDate] DESC

and it runs fast, as you've verified. 你已经验证了,它运行得很快。

Apparently, you do need the pagination, so let's see what we can do. 显然,你确实需要分页,所以让我们看看我们能做些什么。

The reason why your current version is slow, because it scans the whole table first, calculates row number for each and every row and only then returns 10 rows. 您当前版本的原因很慢,因为它首先扫描整个表,计算每行的行数,然后返回10行。 I was wrong here. 我错了。 SQL Server optimizer is pretty smart. SQL Server优化器非常智能。 The root of your problem is somewhere else. 问题的根源在于其他地方。 See my update below. 请参阅下面的更新。


BTW, as other people mentioned, this pagination will work correctly only if SentDate column is unique. BTW,正如其他人所提到的,只有SentDate列是唯一的,这个分页才能正常工作。 If it is not unique, you need to ORDER BY SentDate and another unique column like some ID to resolve ambiguity. 如果它不是唯一的,则需要ORDER BY SentDate和另一个唯一的列(如某个ID来解决歧义。

If you don't need ability to jump straight to particular page, but rather always start with page 1, then go to next page, next page and so on, then the proper efficient way to do such pagination is described in this excellent article: http://use-the-index-luke.com/blog/2013-07/pagination-done-the-postgresql-way The author uses PostgreSQL for illustration, but the technique works for MS SQL Server as well. 如果您不需要直接跳转到特定页面,而是始终从第1页开始,然后转到下一页,下一页等等,那么在这篇优秀的文章中描述了执行此类分页的正确有效方法: http://use-the-index-luke.com/blog/2013-07/pagination-done-the-postgresql-way作者使用PostgreSQL进行说明,但该技术也适用于MS SQL Server。 It boils down to remembering the ID of the last row on the shown page and then using this ID in the WHERE clause with appropriate supporting index to retrieve the next page without scanning all previous rows. 它归结为记住所显示页面上最后一行的ID ,然后在WHERE子句中使用此ID以及相应的支持索引来检索下一页而不扫描所有先前的行。

SQL Server 2008 doesn't have a built-in support for pagination, so we'll have to use workaround. SQL Server 2008没有内置的分页支持,因此我们必须使用变通方法。 I will show one variant that allows to jump straight to a given page and would work fast for first pages, but would become slower and slower for further pages. 我将展示一个允许直接跳转到给定页面的变体,并且可以快速地用于第一页,但对于其他页面将变得越来越慢。

You will have these variables ( PageSize , PageNumber ) in your C# code. 您将在C#代码中包含这些变量( PageSizePageNumber )。 I put them here to illustrate the point. 我把它们放在这里来说明这一点。

DECLARE @VarPageSize int = 10; -- number of rows in each page
DECLARE @VarPageNumber int = 3; -- page numeration is zero-based

SELECT TOP (@VarPageSize)
    [Extent1].[LinkID] AS [LinkID]
    ,[Extent1].[Title] AS [Title]
    ,[Extent1].[Url] AS [Url]
    ,[Extent1].[Description] AS [Description]
    ,[Extent1].[SentDate] AS [SentDate]
    ,[Extent1].[VisitCount] AS [VisitCount]
    ,[Extent1].[RssSourceId] AS [RssSourceId]
    ,[Extent1].[ReviewStatus] AS [ReviewStatus]
    ,[Extent1].[UserAccountId] AS [UserAccountId]
    ,[Extent1].[CreationDate] AS [CreationDate]
FROM
    (
        SELECT TOP((@VarPageNumber + 1) * @VarPageSize)
            [Extent1].[LinkID] AS [LinkID]
            ,[Extent1].[Title] AS [Title]
            ,[Extent1].[Url] AS [Url]
            ,[Extent1].[Description] AS [Description]
            ,[Extent1].[SentDate] AS [SentDate]
            ,[Extent1].[VisitCount] AS [VisitCount]
            ,[Extent1].[RssSourceId] AS [RssSourceId]
            ,[Extent1].[ReviewStatus] AS [ReviewStatus]
            ,[Extent1].[UserAccountId] AS [UserAccountId]
            ,[Extent1].[CreationDate] AS [CreationDate]
        FROM [dbo].[Links] AS [Extent1]
        ORDER BY [Extent1].[SentDate] DESC
    ) AS [Extent1]
ORDER BY [Extent1].[SentDate] ASC
;

The first page is rows 1 to 10, second page is 11 to 20 and so on. 第一页是第1到第10行,第二页是第11到第20页,依此类推。 Let's see how this query works when we try to get the fourth page, ie rows 31 to 40. PageSize=10 , PageNumber=3 . 让我们看看当我们尝试获取第四页时这个查询是如何工作的,即第31行到第40行PageSize=10PageNumber=3 In the inner query we select first 40 rows. 在内部查询中,我们选择前40行。 Note, that we don't scan the whole table here, we scan only first 40 rows. 注意,我们这里扫描整个表,我们只扫描前40行。 We don't even need explicit ROW_NUMBER() . 我们甚至不需要显式的ROW_NUMBER() Then we need to select last 10 rows out of those found 40, so outer query selects TOP(10) with ORDER BY in the opposite direction. 然后我们需要从找到的那些中选择最后10行40,因此外部查询在相反的方向上选择带有ORDER BY TOP(10) As is this will return rows 40 to 31 in reverse order. 这样就会以相反的顺序返回行40到31。 You can sort them back into correct order on the client, or add one more outer query, which simply sorts them again by SentDate DESC . 您可以在客户端上将它们重新排序为正确的顺序,或者再添加一个外部查询,只需通过SentDate DESC它们进行SentDate DESC Like this: 像这样:

SELECT
    [Extent1].[LinkID] AS [LinkID]
    ,[Extent1].[Title] AS [Title]
    ,[Extent1].[Url] AS [Url]
    ,[Extent1].[Description] AS [Description]
    ,[Extent1].[SentDate] AS [SentDate]
    ,[Extent1].[VisitCount] AS [VisitCount]
    ,[Extent1].[RssSourceId] AS [RssSourceId]
    ,[Extent1].[ReviewStatus] AS [ReviewStatus]
    ,[Extent1].[UserAccountId] AS [UserAccountId]
    ,[Extent1].[CreationDate] AS [CreationDate]
FROM
    (
        SELECT TOP (@VarPageSize)
            [Extent1].[LinkID] AS [LinkID]
            ,[Extent1].[Title] AS [Title]
            ,[Extent1].[Url] AS [Url]
            ,[Extent1].[Description] AS [Description]
            ,[Extent1].[SentDate] AS [SentDate]
            ,[Extent1].[VisitCount] AS [VisitCount]
            ,[Extent1].[RssSourceId] AS [RssSourceId]
            ,[Extent1].[ReviewStatus] AS [ReviewStatus]
            ,[Extent1].[UserAccountId] AS [UserAccountId]
            ,[Extent1].[CreationDate] AS [CreationDate]
        FROM
            (
                SELECT TOP((@VarPageNumber + 1) * @VarPageSize)
                    [Extent1].[LinkID] AS [LinkID]
                    ,[Extent1].[Title] AS [Title]
                    ,[Extent1].[Url] AS [Url]
                    ,[Extent1].[Description] AS [Description]
                    ,[Extent1].[SentDate] AS [SentDate]
                    ,[Extent1].[VisitCount] AS [VisitCount]
                    ,[Extent1].[RssSourceId] AS [RssSourceId]
                    ,[Extent1].[ReviewStatus] AS [ReviewStatus]
                    ,[Extent1].[UserAccountId] AS [UserAccountId]
                    ,[Extent1].[CreationDate] AS [CreationDate]
                FROM [dbo].[Links] AS [Extent1]
                ORDER BY [Extent1].[SentDate] DESC
            ) AS [Extent1]
        ORDER BY [Extent1].[SentDate] ASC
    ) AS [Extent1]
ORDER BY [Extent1].[SentDate] DESC

This query (as original query) would work always correctly only if SentDate is unique. 仅当SentDate是唯一的时,此查询(作为原始查询)才能始终正常工作。 If it is not unique, add unique column to the ORDER BY . 如果它不唯一,请将唯一列添加到ORDER BY For example, if LinkID is unique, then in the inner-most query use ORDER BY SentDate DESC, LinkID DESC . 例如,如果LinkID是唯一的,那么在最内层查询中使用ORDER BY SentDate DESC, LinkID DESC In the outer query reverse the order: ORDER BY SentDate ASC, LinkID ASC . 在外部查询中反转顺序: ORDER BY SentDate ASC, LinkID ASC

Obviously, if you want to jump to page 1000, then the inner query would have to read 10,000 rows, so the further you go, the slower it gets. 显然,如果你想跳转到第1000页,那么内部查询必须读取10,000行,所以越往前走,它就越慢。

In any case, you need to have an index on SentDate (or SentDate, LinkID ) to make it work. 在任何情况下,您都需要在SentDate (或SentDate, LinkID )上SentDate索引才能使其正常工作。 Without an index the query would scan the whole table again. 如果没有索引,查询将再次扫描整个表。

I'm not telling you here how to translate this query to EF, because I don't know. 我不是在这里告诉你如何将这个查询翻译成EF,因为我不知道。 I never used EF. 我从未使用EF。 There may be a way. 可能有办法。 Also, apparently, you can just force it to use actual SQL, rather than trying to play with C# code. 此外,显然,您可以强制它使用实际的SQL,而不是尝试使用C#代码。

Update 更新

Execution plans comparison 执行计划比较

In my database I have a table EventLogErrors with 29,477,859 rows and I compared on SQL Server 2008 the query with ROW_NUMBER that EF generates and what I suggested here with TOP . 在我的数据库中,我有一个包含29,477,859行的表EventLogErrors ,我在SQL Server 2008上将该查询与EF生成的ROW_NUMBER以及我在这里建议的TOP I tried to retrieve the fourth page 10 rows long. 我试图检索第10页10行长。 In both cases optimizer was smart enough to read only 40 rows, as you can see from the execution plans. 在这两种情况下,优化器都足够智能,只能读取40行,正如您可以从执行计划中看到的那样。 I used a primary key column for ordering and pagination for this test. 我使用主键列进行此测试的排序和分页。 When I used another indexed column for pagination results were the same, ie both variants read only 40 rows. 当我使用另一个索引列进行分页时,结果是相同的,即两个变体只读取40行。 Needless to say, both variants returned results in a fraction of a second. 毋庸置疑,两种变体都会在几分之一秒内返回。

Variant with TOP 变种与TOP

变种与TOP

Variant with ROW_NUMBER 变体与ROW_NUMBER

变体与ROW_NUMBER

What it all means is that the root of your problem is somewhere else. 这一切意味着问题的根源在于其他地方。 You mentioned that your query runs slowly only sometimes and I didn't really pay attention to it originally. 你提到你的查询有时候运行缓慢,我最初并没有真正关注它。 With such symptom I would do the following: 出现这种症状我会做以下事情:

  • Check execution plan. 检查执行计划。
  • Check that you do have an index. 检查您是否有索引。
  • Check that the index is not heavily fragmented and statistics is not outdated. 检查索引是否没有严重碎片,并且统计信息不会过时。
  • The SQL Server has a feature called Auto-Parameterization . SQL Server具有一个称为自动参数化的功能。 Also, it has a feature called Parameter Sniffing . 此外,它还具有称为参数嗅探的功能。 Also, it has a feature called Execution plan caching . 此外,它还具有称为执行计划缓存的功能。 When all three features work together it may result in using a non-optimal execution plan. 当所有三个功能协同工作时,可能会导致使用非最佳执行计划。 There is an excellent article by Erland Sommarskog explaining it in detail: http://www.sommarskog.se/query-plan-mysteries.html This article explains how to confirm that the problem is really in parameter sniffing by checking the cached execution plan and what can be done to fix the problem. Erland Sommarskog有一篇很好的文章详细解释了它: http//www.sommarskog.se/query-plan-mysteries.html本文解释了如何通过检查缓存的执行计划来确认问题是否真的在参数嗅探中以及如何解决问题。

I'm guessing the WHERE row_number > 0 will change over time as you ask for page 2, page 3, etc... 我猜测,当你要求第2页,第3页等时, WHERE row_number > 0会随时间变化...

As such, I'm curious if it would help to create this index: 因此,我很好奇是否有助于创建此索引:

CREATE INDEX idx_links_SentDate_desc ON [dbo].[Links] ([SentDate] DESC)

In all honesty, IF it works, it's pretty much a band-aid and you'll probably will need to rebuild this index on a frequent basis as I'm guessing it will get fragmented over time... 老实说,如果它有效,它几乎是一个创可贴,你可能需要经常重建这个指数,因为我猜它会随着时间的推移而变得支离破碎......

UPDATE : check the comments! 更新 :检查评论! Turns out the DESC has no effect whatsoever and should be avoided if your data comes in low to high! 原来DESC没有任何影响,如果您的数据从低到高,应该避免!

Sometimes the inner select can cause problems with the execution plan, but it's the easiest way for the expression tree to be built from the code. 有时内部选择会导致执行计划出现问题,但这是从代码构建表达式树的最简单方法。 Usually, it won't affect performance too much. 通常,它不会对性能产生太大影响。

Clearly in this case it does. 显然,在这种情况下确实如此。 One workaround is to use your own query with ExecuteStoreQuery . 一种解决方法是使用您自己的ExecuteStoreQuery查询。 Something like this: 像这样的东西:

int takeNo = 20;
int skipNo = 100;

var results = db.ExecuteStoreQuery<Link>(
    "SELECT LinkID, Title, Url, Description, SentDate, VisitCount, RssSourceId, ReviewStatus, UserAccountId, CreationDate FROM Links", 
    null);

results = results.OrderBy(x=> x.SentDate).Skip(skipNo).Take(takeNo);

Of course you lose a lot of the benefits of using an ORM in the first place by doing this, but it might be acceptable for an exceptional circumstance. 当然,通过这样做,您首先会失去使用ORM的许多好处,但对于特殊情况,这可能是可以接受的。

This looks like a standard paging query. 这看起来像标准的分页查询。 I would guess that you do not have an index on SentDate. 我猜你在SentDate上没有索引。 If so, the first thing to try is adding an index on SentDate and seeing what kind of impact this has on performance. 如果是这样,首先要尝试的是在SentDate上添加一个索引,看看它对性能产生了什么样的影响。 Assuming that you do not always want to sort/page on SentDate and that indexing every column that you might want to sort/page by is not going to happen, take a look at this other stackoverflow question . 假设您并不总是希望对SentDate进行排序/分页,并且索引每个您可能想要排序/分页的列都不会发生,请查看此其他stackoverflow问题 In some cases, SQL Server's "Gather Streams" parallelism operation can overflow into TempDb. 在某些情况下,SQL Server的“Gather Streams”并行操作可能会溢出到TempDb中。 When this happens, performance goes into the toilet. 当发生这种情况时,性能会进入厕所。 As the other answer says, Indexing the column can help, as can disabling parallelism. 正如另一个答案所说,索引列可能会有所帮助,因为可以禁用并行性。 Check out your query plan and see if it looks like this might be the issue. 查看您的查询计划,看看是否可能出现问题。

I am not very good in EF but can give you hints. 我不是很擅长EF,但可以给你提示。 First of all you have to check if you have an non-clustered index on [Extent1].[SentDate]. 首先,您必须检查[Extent1]上是否有非聚集索引。[SentDate]。 Second if not, create, if exists, then recreate or re-arrange it. 如果不存在,则创建(如果存在),然后重新创建或重新排列它。

Third change your query like this. 第三个像这样更改您的查询。 As your original SQL is nothing just written un-necessary complex and it would result same as this one I am showing here. 因为你原来的SQL并不是简单的写入不必要的复杂,它会产生与我在这里展示的相同。 Try to write things simple, will work faster and maintenance would also be easy. 尝试编写简单的东西,工作更快,维护也很容易。

SELECT TOP (10) 
[Extent1].[LinkID] AS [LinkID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Url] AS [Url], 
[Extent1].[Description] AS [Description], 
[Extent1].[SentDate] AS [SentDate], 
[Extent1].[VisitCount] AS [VisitCount], 
[Extent1].[RssSourceId] AS [RssSourceId], 
[Extent1].[ReviewStatus] AS [ReviewStatus], 
[Extent1].[UserAccountId] AS [UserAccountId], 
[Extent1].[CreationDate] AS [CreationDate]
FROM [dbo].[Links] AS [Extent1]
ORDER BY [Extent1].[SentDate] DESC

or modify this one little bit like this if case it result different. 如果它的结果​​不同,或者修改这个有点像这样。

select top 10 A.* from (
SELECT * from
[Extent1].[LinkID] AS [LinkID], 
[Extent1].[Title] AS [Title], 
[Extent1].[Url] AS [Url], 
[Extent1].[Description] AS [Description], 
[Extent1].[SentDate] AS [SentDate], 
[Extent1].[VisitCount] AS [VisitCount], 
[Extent1].[RssSourceId] AS [RssSourceId], 
[Extent1].[ReviewStatus] AS [ReviewStatus], 
[Extent1].[UserAccountId] AS [UserAccountId], 
[Extent1].[CreationDate] AS [CreationDate]
FROM [dbo].[Links] AS [Extent1] ) A
ORDER BY A.[SentDate] DESC 

I am 99% sure it will work. 我99%肯定它会起作用。

Have you tried chaining in the method? 你试过链接方法吗?

        IQueryable<TEntity> query = _dbSet;
        return query.Where(x => (filter != null ? filter : x)
                    .Where(x => (orderBy != null ? orderBy : x));

I am wondering if this will change the query that is created by EF. 我想知道这是否会改变EF创建的查询。

I have run into similar issues before where EF will decide to decorate the SQL it decides to run in a very non-performant fashion. 在EF决定装饰它决定以非常高效的方式运行的SQL之前,我遇到过类似的问题。

Anyways, to provide a possible solution to your question: 无论如何,为您的问题提供可能的解决方案:

On instances where I don't like what EF does with my code to generate SQL statements, I end up writing a stored procedure, import that into my EDMX as a function and use that to retrieve my data. 在我不喜欢EF用我的代码生成SQL语句的情况下,我最终编写了一个存储过程,将其作为函数导入到我的EDMX中并使用它来检索我的数据。 It affords me control on how to formulate the SQL and I know exactly what index I need to leverage to get the best performance out of this. 它使我能够控制如何制定SQL,并且我确切地知道需要利用哪个索引来获得最佳性能。 I imagine you know how to write a stored proc and import that as a function into EF so I will leave those details out. 我想你知道如何编写一个存储过程并将其作为函数导入EF中,所以我将把这些细节留下来。 Hope this helps you. 希望这对你有所帮助。

I will still keep checking this page to see if someone comes up with a nicer, less painful solution to your issue. 我仍会继续查看此页面,看看是否有人为您的问题提出了更好,更少痛苦的解决方案。

Your code looks like somewhat obscure for me, And this is first time where I encounter such this querying. 你的代码对我来说有点模糊,这是我第一次遇到这样的查询。 As you told, sometimes It takes too long time to execute, so it tells the query can be interpreted in another ways somewhere, perhaps by ignoring EF performance considerations in some cases, So try to rearrange query conditions/selections and consider lazy loading in your program logic . 正如您所说,有时执行需要太长时间,因此它告诉查询可以在某处以其他方式解释,可能在某些情况下忽略EF性能注意事项 ,因此请尝试重新排列查询条件/选择考虑延迟加载程序逻辑

Aren't you bitten by the Statistic update problem in SQL server? 你不是被SQL服务器中的Statistic更新问题所困扰吗?

ALTER DATABASE YourDBName SET AUTO_UPDATE_STATISTICS_ASYNC ON ALTER DATABASE YourDBName SET AUTO_UPDATE_STATISTICS_ASYNC ON

Default is OFF, thereby your SQL server will stall when 20% of your data has changed - waiting for the Statistics update before running the query. 默认为OFF,因此当20%的数据发生更改时,SQL Server将停止 - 在运行查询之前等待Statistics更新。

Call me crazy, but it looks like you've got the thing ordering itself with itself when this code is called: 叫我疯了,但看起来你在调用这段代码的时候已经有了自己的事情:

if (orderBy != null)
{
    query = orderBy(query);
}

I think that would explain the whole "sometimes it's slow" bit. 我认为这可以解释整个“有时它很慢”的一点。 Probably runs fine until you have something in the orderBy parameter, then it's calling itself and creating that row numbered sub-select that slows it down. 可能运行正常,直到你在orderBy参数中有东西,然后它调用自己并创建编号为sub-select的行减慢它。

Try commenting out the query = orderBy(query) portion of your code and see if you still get the slow down. 尝试注释掉代码的query = orderBy(query)部分,看看你是否仍然放慢速度。 I'm betting that you won't. 我打赌你不会。

Also, you can simplify your code using Dynamic LINQ . 此外,您可以使用Dynamic LINQ简化代码。 It basically lets you specific sorting with a string name of a field ( .orderby("somefield") ) instead of trying to pass in a method, which I've found to be a lot easier. 它基本上允许你使用字段的字符串名称( .orderby("somefield") )进行特定排序,而不是尝试传入一个方法,我发现它更容易。 I use that in MVC apps to handle sorting by whatever field the users clicks on a grid. 我在MVC应用程序中使用它来处理用户在网格上点击的任何字段的排序。

尝试在SentDate上添加非聚集索引

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM