我有一个超过300万行的巨大数据库(我的用户信息),我需要选择当天有生日的所有用户。
生日列是text
(例如'19 / 03'或'19 / 1975/1975'),包含日期和月份,有时还有年份。
当我尝试选择具有左侧函数的行时,返回结果需要花费一分多钟时间。
我尝试为day
,month
和year
使用3个int列,然后进行选择,但需要更长时间才能得到结果。
关于如何让它跑得更快的任何想法?
我正在使用SQL Server 2008
由于
答案 0 :(得分:2)
正如marc_s所提到的,如果可能的话,将其存储为日期类型 - 它将使SQL Server更快地执行比较,并且它将更容易维护。接下来,确保在该列上放置索引,并考虑包括任何额外的列,如果您只是查找生日以选择总行的一小部分。
最后 - 这是一个很大的问题。 TEXT是您可以选择的最差数据类型。存储TEXT的方式,数据实际上并不存储在页面本身上。相反,它留下了一个指向另一个页面的16字节指针。然后,该其他页面将在记录中包含数据本身。但是它变得更糟,当数据长度在0到64个字节之间时,该记录将是一个占用84字节空间的SMALL_ROOT数据类型!
因此,可以保存为8字节日期时间或4字节日期的内容现在占用总共100个字节,并导致每行的行外查找。基本上是糟糕表现的完美风暴。
如果您无法将其更改为更合适的日期时间,请至少将其更改为varchar!
答案 1 :(得分:1)
首先以SQL Server支持的格式保存日期,例如DATE
或DATETIME
(在您的情况下,我猜DATE
应该就够了)您可以使用MONTH
和DAY
之类的SQL函数,如下所示,避免复杂的字符串操作函数,如LEFT等。
您的查询将如下所示:
select * from MyTable where MONTH(dateColumnA) = '1' && DAY(dateColumnB) ='7' --1 is for january
我不确定这是否会完全解决您的性能问题,但您可以在SQL查询分析器中运行此查询并查看它对索引等的推荐。我对日期类型的索引没有太多的了解列
答案 2 :(得分:0)
我要说的大部分内容都已经说过:使用DATE类型来存储日期,并确保将其编入索引。如果您要使用三个整数来存储日期并按其搜索,那么请确保它们也被编入索引:
CREATE INDEX IX_MyTable_Date_Ints ON MyTable(intYear, intMonth, intDay)
CREATE INDEX IX_MyTable_Date ON MyTable(BirthDate)
如果您希望能够在用户表中搜索除年份之外的生日,我建议使用固定年份将生日存储在不同的日期字段中,例如3004 - 而不是使用三个整数。您的基准年应为闰年,以满足可能在2月29日出生的任何人。如果您将来使用一年,您可以使用年份来确定日期实际上是应该忽略年份的日期。
然后你可以通过添加“WHERE birth_day ='3004-12-10'来搜索生日,无论年份如何,而不必对每条记录进行函数调用。如果这个字段被编入索引,你应该是能够在闪存中返回所有匹配的行。你需要记住,在搜索索引时,服务器最多需要进行32次比较才能找到40亿条记录中的匹配。永远不要低估索引的好处! / p>
我倾向于通过触发器保持生日,以便它保持自己更新。对于没有年份的出生日期,只需使用基准年(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)
希望这有帮助。
答案 3 :(得分:0)
尝试使用Result Set而不是DataTable或DataSet。与这两个
相比,ResultSet很快