我有一个大约800万行的数据库,我想从中随机选择n行.首先,我在
StackOverflow和
MSDN的文章中阅读了流行的和类似的问题,但我觉得答案仍然不符合我的需要.
@H_403_25@解决方法
如果我想在没有额外条件的情况下随机选择一定比例的行,所提供的解决方案效果很好但是我想要随机选择n行(例如最多5行),所有这些都匹配某个条件.
我的数据库包含包含其词性,标记,引理和令牌等信息的单词.现在我想执行查询以选择5个与查询中的单词类似的随机单词(例如,给我5个类似于模糊的单词),这是通过仅查看具有相同词性和单词的值来确定的. levenshtein距离超过一定阈值.我在sql server中有一个函数可以计算levenshtein距离.
上述方法的问题在于它们要么必须遍历所有记录并计算levenshtein距离(这需要花费很多时间!),或者它们只允许我选择百分比而不是n行.
一个运行得很好的查询是:
SELECT DISTINCT TOP 5 lower(Words.TOKEN) as LTOKEN,Words.LEMMA,TagSet.POS_Simplified,TagSet.TAG FROM Words JOIN TagSet on Words.TAG = TagSet.TAG WHERE NOT Words.LEMMA = 'monarchie' AND TagSet.POS_Simplified = 'noun' AND TagSet.TAG = 'NOM' AND NOT Words.TOKEN = 'monarchie' AND [dbo].edit_distance('monarchie',Words.Token) > 0.5
然而,只有顶部我总是得到相同的结果.我需要我的上衣是随机的.像使用NEWID()这样的方法将首先遍历整个数据库,然后随机选择,这不是我想要的行为,因为它们占用时间太长.
编辑:
有人(不在StackOverflow上)可能为我提供了一个OPTION子句和fast关键字的解决方案,该关键字检索它找到的前n行.
使用OPTION(快5)我到目前为止获得了最佳性能(在800万行表上有10秒).我还将Levenshtein函数从sql实现更改为c#编写的库实现,这大大加快了性能.
Select top 5 * from ( SELECT DISTINCT lower(Words.TOKEN) as LTOKEN,TagSet.TAG FROM Words JOIN TagSet on Words.TAG = TagSet.TAG WHERE NOT Words.LEMMA = 'monarchie' AND TagSet.POS_Simplified = 'noun' AND TagSet.TAG = 'NOM' AND NOT Words.TOKEN = 'monarchie' AND [dbo].clrEditDistance('monarchie',Words.Token) > 0.5 ) AS T ORDER BY NEWID() OPTION(fast 5)
避免全面扫描将很困难.如果您有一个可以随意选择的列,比如说您碰巧有一个“密集”的标识列,间隙很小,请用以下修改代替Klark的方法:
declare @results table (id bigint,name varchar(100)) while (select count(*) from @results) < 5 begin insert @results (name) select name from ( select * from dbo.Words WHERE IDCOLUMN = CONVERT(INT,RAND()) * APPX_NUMBER_OF_ROWS ) as SubQueryAlias where dbo.edit_distance(left(name,4),'APRS',100) < 3 end select * from @results)