Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/sql/74.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql 从大型数据库中选择行的最快方法是什么?_Sql_Sql Server_Sql Server 2008 - Fatal编程技术网

Sql 从大型数据库中选择行的最快方法是什么?

Sql 从大型数据库中选择行的最快方法是什么?,sql,sql-server,sql-server-2008,Sql,Sql Server,Sql Server 2008,我有一个超过300万行的庞大数据库(我的用户信息),我需要选择所有在当天有生日的用户 生日栏是一个文本(例如'19/03'或'19/03/1975'),带有日期和月份,有时还有年份 当我尝试选择具有类似左函数的行时,返回结果需要一分钟以上的时间 我尝试使用3个int列来表示日、月和年,然后进行选择,但要得到结果需要更长的时间 有没有办法让它跑得更快 我正在使用SQLServer2008 谢谢首先,以SQL Server支持的格式保存日期,例如日期或日期时间(在您的情况下,我猜日期应该足够了)一旦

我有一个超过300万行的庞大数据库(我的用户信息),我需要选择所有在当天有生日的用户

生日栏是一个
文本
(例如'19/03'或'19/03/1975'),带有日期和月份,有时还有年份

当我尝试选择具有类似左函数的行时,返回结果需要一分钟以上的时间

我尝试使用3个int列来表示
,然后进行选择,但要得到结果需要更长的时间

有没有办法让它跑得更快

我正在使用SQLServer2008


谢谢

首先,以SQL Server支持的格式保存日期,例如
日期
日期时间
(在您的情况下,我猜
日期
应该足够了)一旦有了它,您就可以按如下方式使用SQL函数,如
MONTH
DAY
,并避免复杂的字符串操作函数,如LEFT等

您的查询将如下所示:

select * from MyTable where MONTH(dateColumnA) = '1' && DAY(dateColumnB) ='7' --1 is for january

我不确定这是否能完全解决性能问题,但您可以在SQL query Analyzer中运行此查询,看看它对索引等提出了什么建议。我对日期类型列上的索引不太了解。首先,以SQL Server支持的格式保存日期比如
DATE
或者
DATETIME
(在你的例子中,我猜
DATE
应该足够了)一旦你有了它,你就可以使用SQL函数,比如
MONTH
DAY
,如下所示,避免像LEFT等复杂的字符串操作函数

您的查询将如下所示:

select * from MyTable where MONTH(dateColumnA) = '1' && DAY(dateColumnB) ='7' --1 is for january

我不确定这是否能完全解决您的性能问题,但您可以在SQL query Analyzer中运行此查询,看看它对索引等提出了什么建议。我不太了解日期类型列上的索引,正如marc_提到的,如果可能的话,将其存储为日期类型—这将加快SQL Server对其执行比较的速度,并且更易于维护。下一步,确保在该列上设置索引,如果只查看生日来选择总行的小子集,可以考虑包括任何额外的列。

最后,这是一个大问题。文本几乎是您可以选择的最糟糕的数据类型。按照文本的存储方式,数据实际上并不存储在页面本身。相反,它会留下一个指向另一页的16字节指针。然后,另一个页面将在记录中包含数据本身。但更糟糕的是,当数据长度在0到64字节之间时,该记录将是一个占用84字节空间的小根数据类型

因此,原本可以保存为8字节datetime或4字节date的内容现在总共占用100字节,并导致每行都进行行外查找。基本上,完美风暴的表现不佳


如果您不能将其更改为更合适的日期时间,至少,请将其更改为varchar

正如marc_提到的,如果可能的话,将其存储为日期类型-这将使SQL Server更快地对其执行比较,并且更易于维护。下一步,确保在该列上设置索引,如果只查看生日来选择总行的小子集,可以考虑包括任何额外的列。

最后,这是一个大问题。文本几乎是您可以选择的最糟糕的数据类型。按照文本的存储方式,数据实际上并不存储在页面本身。相反,它会留下一个指向另一页的16字节指针。然后,另一个页面将在记录中包含数据本身。但更糟糕的是,当数据长度在0到64字节之间时,该记录将是一个占用84字节空间的小根数据类型

因此,原本可以保存为8字节datetime或4字节date的内容现在总共占用100字节,并导致每行都进行行外查找。基本上,完美风暴的表现不佳


如果您不能将其更改为更合适的日期时间,至少,请将其更改为varchar

我要说的大部分已经说过了:使用日期类型存储日期,并确保它已被索引。如果要使用这三个整数存储日期并按其进行搜索,请确保它们也已编制索引:

CREATE INDEX IX_MyTable_Date_Ints ON MyTable(intYear, intMonth, intDay)
CREATE INDEX IX_MyTable_Date ON MyTable(BirthDate)
如果您希望能够在用户表中搜索不包括年份的生日,我建议将生日存储在不同的日期字段中,使用固定年份,例如3004,而不是使用三个整数。你的基准年应该是闰年,以迎合任何可能在2月29日出生的人。如果您使用的是遥远的将来的一年,则可以使用该年来确定某个日期实际上是应该忽略该年的日期

然后,您可以搜索生日,不管是哪一年,无需对每条记录执行函数调用,方法是添加“其中出生日='3004-12-10'。如果该字段已编制索引,您应该能够在闪存中返回所有匹配的行。您需要记住,在搜索索引时,服务器最多需要进行32次比较,才能在40亿条记录中找到匹配项。永远不要低估索引的好处

我倾向于通过触发器来维护生日,这样它就可以保持自身的更新。对于那些没有年份的出生日期,只需使用基准年(3004)。因为你的基准年是在未来,你知道这个出生日期没有年份

CREATE TABLE MyTable (
    MyTable_key INT IDENTITY(1, 1),
    username VARCHAR(30),
    birth_date DATE,
    birth_day DATE
)
ALTER TABLE MyTable ADD CONSTRAINT PK_MyTable PRIMARY KEY CLUSTERED (MyTable_key)
CREATE INDEX MyTable_birth_date ON MyTable(birth_date)
CREATE INDEX MyTable_birth_day ON MyTable(birth_day)
GO
CREATE TRIGGER tr_MyTable_calc_birth_day ON MyTable AFTER INSERT, UPDATE AS
    UPDATE t SET birth_day = DATEADD(YEAR, 3004-DATEPART(YEAR, t.birth_date), t.birth_date)
    FROM MyTable t, inserted i WHERE i.MyTable_key = t.MyTable_key
要更新现有表,请以独立查询的形式运行更新,而不使用触发器中使用的插入表的联接:

    UPDATE MyTable SET birth_day = DATEADD(YEAR, 3004-DATEPART(YEAR, birth_date), birth_date)

希望这能有所帮助。

我要说的大部分已经说过:使用日期类型存储日期,并确保它已被索引。如果你要去我们这里