在数据库表中有效地查找唯一值

时间:2010-02-11 17:01:10

标签: asp.net sql sql-server asp.net-mvc database

我有一个包含大量行的数据库表。此表表示系统记录的消息。每条消息都有一个消息类型,并将其存储在表中的自己的字段中。我正在编写一个用于查询此消息日志的网站。如果我想按消息类型进行搜索,那么理想情况下我希望有一个下拉框,列出数据库中出现的消息类型。消息类型可能会随着时间的推移而发生变化,因此我无法将类型硬编码到下拉列表中。我将不得不做一些查找。迭代整个表内容以查找唯一的消息值显然是非常愚蠢但是在数据库字段中是愚蠢的我在这里要求更好的方法。也许一个单独的查找表,数据库偶尔会更新,列出我可以填充下拉的唯一消息类型,这将是一个更好的主意。

我们非常感谢任何建议。

我正在使用的平台是ASP.NET MVC和SQL Server 2005

9 个答案:

答案 0 :(得分:9)

一个单独的查找表,其中包含存储在日志中的消息类型的ID。这将减小日志并提高日志效率。它也会Normalize您的数据。

答案 1 :(得分:5)

是的,我肯定会使用单独的查找表。然后,您可以使用以下内容填充它:

INSERT TypeLookup (Type)
SELECT DISTINCT Type
FROM BigMassiveTable

然后,您可以定期运行充值作业,从主表中提取查找表中尚不存在的新类型。

答案 2 :(得分:2)

SELECT  DISTINCT message_type
FROM    message_log

是最直接但不是非常有效的方式。

如果你有一个可以可能出现在日志中的类型列表,请使用:

SELECT  message_type
FROM    message_types mt
WHERE   message_type IN
        (
        SELECT  message_type
        FROM    message_log
        )

如果将message_log.message_type编入索引,这将更有效。

如果您没有此表但想要创建一个表,并且message_log.message_type已编入索引,请使用递归CTE来模拟松散索引扫描:

WITH    rows (message_type) AS
        (
        SELECT  MIN(message_type) AS mm
        FROM    message_log
        UNION ALL
        SELECT  message_type
        FROM    (
                SELECT  mn.message_type, ROW_NUMBER() OVER (ORDER BY mn.message_type) AS rn
                FROM    rows r
                JOIN    message_type mn
                ON      mn.message_type > r.message_type
                WHERE   r.message_type IS NOT NULL
                ) q
        WHERE   rn = 1
        )
SELECT  message_type
FROM    rows r
OPTION (MAXRECURSION 0)

答案 3 :(得分:1)

我只是想说明一点:规范化数据。

message_types
message_type | message_type_name

messages
message_id | message_type | message_type_name

然后你就可以不用任何缓存的DISTINCT:

为您的下拉列表

SELECT * FROM message_types

供您检索

SELECT * FROM messages WHERE message_type = ? 

SELECT m.*, mt.message_type_name FROM messages AS m
JOIN message_types AS mt
ON ( m.message_type = mt.message_type)

我不确定为什么你需要一个你必须更新的缓存DISTINCT,当你可以稍微调整架构并使用RI时。

答案 4 :(得分:1)

在消息类型上创建索引:

CREATE INDEX IX_Messages_MessageType ON Messages (MessageType)

然后,要获取唯一消息类型的列表,请运行:

SELECT DISTINCT MessageType
FROM Messages
ORDER BY MessageType

因为索引是按照 MessageType 的顺序进行物理排序的,所以SQL Server可以非常快速地高效地,扫描索引,选择一个唯一的消息类型列表。

表演并不差 - 这是SQL Server擅长的。


不可否认,您可以通过“消息类型”表来节省一些空间。如果您一次只显示几条消息:那么当书签查找连接回MessageTypes表时,书签查找将不会成为问题。但是,如果您一次开始显示数百或数千条消息,那么返回消息类型的连接可能会变得非常昂贵且不必要,并且将MessageType存储为更快消息。

但是我在MessageType列上创建索引并选择distinct没有问题。 SQL Server喜欢那种东西。但是,如果你发现它是服务器上的真正负载,一旦你每秒获得几十次点击,那么请按照其他建议将其缓存在内存中。

我的个人解决方案是:

  • 创建索引
  • 选择不同

如果我还有问题

  • 内存缓存在30秒后过期

关于规范化/非规范化问题。规范化可以节省空间,在连续执行连接时以CPU为代价。但是,否定化的逻辑点是避免重复数据,这可能导致数据不一致。

您是否打算更改消息类型的文本,如果您使用消息存储,则必须更新所有行?

或者有没有什么可说的,因为在消息发布时消息类型 <请求客户端响应“?

答案 5 :(得分:0)

您是否考虑过索引视图?它的结果集已实现并存储在存储中,因此查找的开销与您尝试执行的任何操作的其余部分分开。

当数据发生变化时,SQL Server会自动更新视图,它会更改视图的内容,因此在这方面它不如Oracle实现的灵活性。

答案 6 :(得分:0)

MessageType应该是主表中的外键到包含消息类型代码和描述的定义表。这将大大提高您的查找性能。

这样的东西
DECLARE @MessageTypes TABLE(
        MessageTypeCode VARCHAR(10),
        MessageTypeDesciption VARCHAR(100)
)

DECLARE @Messages TABLE(
        MessageTypeCode VARCHAR(10),
        MessageValue VARCHAR(MAX),
        MessageLogDate DATETIME,
        AdditionalNotes VARCHAR(MAX)
)

通过此设计,您的查找应仅查询 MessageTypes

答案 7 :(得分:0)

正如其他人所说,创建一个单独的消息类型表。将记录添加到消息表时,请检查表中是否已存在消息类型。如果没有,请添加它。在任何一种情况下,然后将标识符从消息类型表发布到消息表中。这应该为您提供标准化数据。是的,当您添加记录时,这是一个额外的时间,但在检索时应该更有效。

如果有更多的添加然后读取,如果“消息类型”很短,一个完全不同的方法是仍然创建单独的消息类型表,但在添加时不要引用它,并且只更新懒散地,按需。

即,(a)在每条消息记录中包含时间戳。 (b)保留上次检查时找到的消息类型列表。 (c)每次检查时,搜索自上次添加的任何新消息类型,如:

create table temp_new_types as
    (select distinct message_type
    from message
    where timestamp>last_type_check
);

insert into message_type_list (message_type)
select message_type
from temp_new_types
where message_type not in (select message_type from message_type_list);

drop table temp_new_types;

然后将此检查的时间戳存储在某处,以便下次可以使用它。

答案 8 :(得分:0)

答案是使用'DISTINCT',每种最佳解决方案对于不同大小的表都是不同的。成千上万,数百万,数十亿?更多 ?这是非常不同的最佳解决方案。