表中的简单 where 语句需要一个小时

Posted

技术标签:

【中文标题】表中的简单 where 语句需要一个小时【英文标题】:Simple where statement from table takes an hour 【发布时间】:2018-04-26 06:41:07 【问题描述】:

我有这么简单的一行:

var records = db.MyDbTable.Where(x => x.SupplierId.HasValue).ToList();

执行需要一小时。我在表中有 272 行。该表有一列是NVARCHAR(MAX),里面有很大的字符串。如何优化语句?之后在代码中我有一个 foreach 遍历记录并处理它们。

db中的select语句需要5分钟。

当我使用 SQL 分析器检查时,这是从 C# 翻译的语句:

SELECT 
    [Extent1].[id] AS [id], 
    [Extent1].[xml] AS [xml], 
    [Extent1].[name] AS [name], 
    [Extent1].[create] AS [create], 
    [Extent1].[sale] AS [sale], 
    [Extent1].[SupplierId] AS [SupplierId], 
    [Extent1].[Success] AS [Success], 
    [Extent1].[IId] AS [IId]
    FROM [dbo].[MyDbTable] AS [Extent1]
    WHERE [Extent1].[SupplierId] IS NOT NULL

【问题讨论】:

我认为我们需要一些关于您的数据库结构的信息。此外,如果您告诉我们在长达一小时的执行后返回了什么结果,这将有所帮助。通常这些问题是表/视图连接不正确的结果,但您的问题似乎表明这是单个表中的标准查找。你能澄清一下吗? 我们应该怎么知道?从您提供的少量信息中,我看不出有太多需要优化的地方,实际上查询已经尽可能简单了-至少从客户端(您的代码)来看,我怀疑您可以做很多事情它。你确定这个声明需要这么多时间吗?你使用了探查器吗? 如果supplierId是外键,如果引用字段和外键字段没有相同的数据类型,那么可能会出现这个问题。 你试过SQL server profiler来找出实际使用的SQL语句吗?您确定要使用 MyDbTable 中所有对象的所有属性吗? 您实际上在进一步处理中使用了该 xml?仍然想知道它们到底有多大(100MB、10MB)? 【参考方案1】:

正如评论中的 OP 所述,xml 字段是必需的。然后正如D T 所说,你应该将它存储在单独的表中。此外,您可以在COMPRESSING 之后在C# 中添加此字段。我给出了一些我使用BLToolKitEntityFramework 测试过的统计数据。

我正在读取带有70000 行的文本文件,每行包含70 字符。那是5,039,998 的长度。以下是我想分享的统计数据。我刚刚测试了 35 条记录,因为没有压缩,数据库中的每一行空间都需要 9MB 左右。

如您所见,OutOfMemory Exception,我没有深入研究。我只是想看看时间。我实际上做的是,

当您在该表中插入数据时;在插入 COMPRESS 字符串之前。该字段的数据类型是varbinary (MAX),我采用了。当您获取数据时;仅在您想要处理它时获取它。不要忘记DECOMPRESS它。在SQL Server 中,需要0 seconds 来获取压缩记录。

下面是压缩和解压的代码。 Reference For The Code

    public static void CopyTo(Stream src, Stream dest)
    
        byte[] bytes = new byte[4096];

        int cnt;

        while ((cnt = src.Read(bytes, 0, bytes.Length)) != 0)
        
            dest.Write(bytes, 0, cnt);
        
    

    public static byte[] Zip(string str)
    
        var bytes = Encoding.UTF8.GetBytes(str);

        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream())
        
            using (var gs = new GZipStream(mso, CompressionMode.Compress))
            
                //msi.CopyTo(gs);
                CopyTo(msi, gs);
            

            return mso.ToArray();
        
    

    public static string Unzip(byte[] bytes)
    
        using (var msi = new MemoryStream(bytes))
        using (var mso = new MemoryStream())
        
            using (var gs = new GZipStream(msi, CompressionMode.Decompress))
            
                //gs.CopyTo(mso);
                CopyTo(gs, mso);
            

            return Encoding.UTF8.GetString(mso.ToArray());
        
    

希望对你有所帮助。

【讨论】:

【参考方案2】:

尝试将 where 字段 (SupplierId) 的索引添加到数据库中,看看是否有帮助。

【讨论】:

NVARCHAR(MAX) 上的索引?我可以建议建立一个checksum 并改为索引吗? 虽然这是此类问题的常见解决方案,但列类型 (nvarchar(max)) 会使索引效率低下;对于 272 行表的 1 小时运行时间,我预计会出现更多问题,而不仅仅是缺少索引。 SupplierId 字段是 int,另一个字段是 nvarchar(max)

以上是关于表中的简单 where 语句需要一个小时的主要内容,如果未能解决你的问题,请参考以下文章

SQL 删除

将表中的日期与 TableAU 中的多个日期范围进行比较:构建 WHERE 语句

DB2 SQL:如何将“WHERE EXISTS”表中的列添加到选择语句

SQL 中 Where 使用的语句

联结表

SQL UPDATE 语句:更新表中的记录语法及案例剖析