2010-04-02 68 views
3

我有了如下表SQL数据库:SQL查询 - 20密尔记录 - 最佳实践返回信息

 
Table: PhoneRecords 
-------------- 
ID(identity Seed) 
FirstName 
LastName 
PhoneNumber 
ZipCode 

很简单直接的表。这张表有超过2000万条记录。我正在寻找最好的方法来完成基于表格区域代码的记录。例如这里是我所做的一个示例查询。

SELECT phonenumber, firstname 
FROM [PhoneRecords] 
WHERE (phone LIKE '2012042%') OR 
     (phone LIKE '2012046%') OR 
     (phone LIKE '2012047%') OR 
     (phone LIKE '2012083%') OR 
     (phone LIKE '2012088%') OR 
     (phone LIKE '2012841%') 

正如你可以看到这是一个丑陋的查询,但它会完成这项工作(我是不是遇到了超时问题)

谁能告诉我要速度/优化的最好方法做上面的查询来显示结果?目前上面的查询需要大约2个小时才能完成9gb 1600mhz内存,i7 930 quadcore OC'd 4.01ghz。我显然拥有执行这样的查询所需的计算机能力,但查询仍然需要很长时间。

+1

你可以提供表上索引的详细信息吗? – 2010-04-02 09:04:18

回答

6

您可能缺少电话号码列上的索引。

CREATE INDEX IX_PHONERECORDS_PHONENUMBER_FIRSTNAME 
    ON dbo.PhoneRecords (PhoneNumber) INCLUDE (FirstName) 

如果没有帮助,发布execution planCTRL+M)。

+2

感谢大家的快速回复。手机没有编入索引,但我现在设置它试图运行查询(使用Union All而不是OR)来查看它是否更快。我会发布我的调查结果,希望任何遇到这个问题的人都能够解决这个问题。 – eqiz 2010-04-02 09:24:46

+0

@eqiz:当你发布信息时,我也会很想知道单独添加索引是否足够,优化程序是否可以处理您的OR,或者如果查询重写有助于优化程序选择最佳计划。 – 2010-04-02 09:37:24

+0

如果使用'union all'会比'或'子句表现更好(或更差),我会感到惊讶 – 2010-04-02 10:06:41

5

首先,您需要列phone上的索引。如果你没有,添加它。

如果它仍然运行缓慢,您可以尝试使用UNION ALL而不是OR,因为优化器可以更轻松地使用它。这是有效的,因为你构建你的条件的方式可以保证结果是不同的。因此,您的查询可以被重写为:

SELECT phonenumber, firstname FROM [PhoneRecords] WHERE phone LIKE '2012042%' 
UNION ALL 
SELECT phonenumber, firstname FROM [PhoneRecords] WHERE phone LIKE '2012046%' 
UNION ALL 
SELECT phonenumber, firstname FROM [PhoneRecords] WHERE phone LIKE '2012047%' 
UNION ALL 
SELECT phonenumber, firstname FROM [PhoneRecords] WHERE phone LIKE '2012083%' 
UNION ALL 
SELECT phonenumber, firstname FROM [PhoneRecords] WHERE phone LIKE '2012088%' 
UNION ALL 
SELECT phonenumber, firstname FROM [PhoneRecords] WHERE phone LIKE '2012041%' 

此查询应该能够使用索引有效地运行。

您应该在运行实际查询之前查看执行计划,并确保没有TABLE SCAN或INDEX SCAN。

+0

联合等同于使用OR语句。 SQL查询优化器不会以任何方式使用相同的计划吗? – uriDium 2010-04-02 09:08:28

+0

解释?你不觉得与MySQL混淆吗? – 2010-04-02 09:13:59

+0

对不起,是的......混淆了!你是对的 - SQL Server没有这个功能。对于SQL Server来说,查看计划的最简单方法是在SSMS中。有一个按钮“显示预计执行计划”。 – 2010-04-02 09:26:01

2

你有没有索引?第一步是在PhoneNumber列中添加一个索引。如果这还不够(我不知道索引列中部分字符串搜索的具体细节),我会建议添加另一个名为“AreaCode”的列,该列可以从PhoneNumber列自动计算。然后你可以在AreaCode列上添加一个索引。

2

第一个也是很明显的问题是你有索引吗?如果您要查询它,您至少需要在电话号码上创建索引。您应该创建一个覆盖索引,其中包含所需的字段以及where子句中的字段,这样计算机在索引中找到行后就不必浪费时间来获取所需的信息。很明显,反过来说,索引越大,查询越慢。

2

你可以分割你的电话号码列:

然后[区号] [电话号码],如果该查询是在应用程序中“最重要的”这个表和比例返回的行/总行是高的,在[地区代码]上添加一个CLUSTERED索引,否则添加一个标准索引。

您也可以保留电话号码列并直接编入索引,这取决于您的应用程序。

1

首先,我会将电话栏拆分为“区号”和“电话号码”。

此外,我会将此数字转换为int;索引将执行得更快。

AreaCode = 2012042 

要快很多,然后

PhoneNumber LIKE '2012042%' 
0

http://igoro.com/archive/precomputed-view-a-cool-and-useful-sql-pattern

创建物化视图,其中包括电话号码的前n个数字,因为它是自己的专栏。然后,您可以根据区号列查询并包含名称。预先计算区域代码,使其不必在每次选择时完成。如果可以帮助,请不要使用or操作符。使用联合来帮助查询计划使用索引。

实际上,您正在运行的查询将执行20,000,000次x次比较,其中x是您每次执行选择时搜索的区号的数量。通过查询一个确切索引的列,你根本不需要去查看表格,索引可以以有效的方式搜索O(log n)我认为。

1

即使您正在执行表扫描(并且即使您有索引,也可能发生这种情况,但如果选择性较低),您的查询应该以比2小时更快的方式执行。如果与其他查询扫描的其他表无关,并且sqlserver max内存足够大,则表的大小足以完全适合sql服务器缓冲池。所以虽然你可以做一些技巧,如添加索引或拆分区域+电话的电话号码,你应该调查sql server的配置以及你的系统配置。