表中的简单 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#
中添加此字段。我给出了一些我使用BLToolKit
和EntityFramework
测试过的统计数据。
我正在读取带有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 语句需要一个小时的主要内容,如果未能解决你的问题,请参考以下文章
将表中的日期与 TableAU 中的多个日期范围进行比较:构建 WHERE 语句