我有一个很大的表,其中有一列包含日期。由于表格太大了,我想请求例如每天的数据,我正试图用以下语句来完成:
SELECT *
FROM [my_db].[dbo].[my_data] where date between '2019-03-25' and '2019-03-26'
到目前为止,当我运行这个查询时,返回了相关的数据(大约10000行(。然而,查询并没有停止,它一直在执行很长一段时间(不知道执行了多长时间,我总是在大约30分钟后停止它(。我想是在寻找更合适的日期。但是,表是排序的,所以我知道不会有任何进一步的日期了。
在这里处理这个问题的最佳方法是什么?有没有办法在没有找到进一步的结果后设置某种超时?或者我应该使用正常的超时,并希望交易及时完成?谢谢
因此,听起来您的查询正在执行table scan
来检索数据。
我们对您的硬件性能一无所知,但对于可能高度分散的大表,这可能是在慢速驱动器上进行的耗时操作,或者IO是一个瓶颈。
您可以通过多种方式快速获得行数的近似值。阅读你提到你在笔记本电脑上做这件事的评论,很可能你是唯一的用户,在这种情况下,大概的数字可能会很高。
最简单的是运行
exec sp_spaceused 'tablename'
您可以查询表上的索引列表
select * from sys.indexes where object_id=Object_Id('tablename')
您还可以使用SSMS中的对象资源管理器详细信息查看所有表及其统计信息的列表,包括行。连接到服务器并从对象资源管理器的列表中展开数据库。打开详细信息面板(F7(,然后单击表格,将填充列表并检索行数。
您也可以在对象资源管理器中展开Tables
,展开特定的表,然后展开Indexes
以查看当前定义的内容。
因为您(可能(在Date
列上没有索引,即使您知道您已经收到了所有符合条件的结果,SQL Server也不会,因为它必须扫描表。如果没有索引,就无法保证一系列行都将按顺序驻留。
这意味着它会直接跳到一端,开始逐页阅读,直到读到最后,检查每一行是否符合您的筛选条件。如果您期望的数据恰好位于它读取的第一个页面上,那就太好了——但SQL Server无法知道它找到了每一个可能符合条件的行——页面碎片等许多因素可能意味着一些行可能存在于构成表数据的页面列表中。
date
列上的索引将非常有帮助,因为这样SQL server就可以直接查找到第一个符合条件的日期的开始,并按顺序读取值,直到到达最后一行,因为数据是排序的,所以它知道它已经到达了末尾。
索引也有助于诸如select count(*)
之类的查询。每个索引(过滤后的索引除外(都包括每一行,但不是每一列-因此,为了获得行计数,SQL Server将扫描最窄的索引,这意味着它将具有尽可能少的IO。
此外,如果您实际上不需要每列,那么执行select *
将对性能产生影响。
如果您的查询具有高度选择性,并且您在date
上有索引,SQL Server将查找索引中所需的行,然后执行书签查找以检索其余列。
然而,这是一个昂贵的操作,因此存在一个阈值,即不值得进行权衡,SQL Server将选择扫描表以避免查找操作。