我有一个Python程序,每隔10分钟查询一次存储在SQL Server中的LIVE更新表。第一次执行时,它会返回正确的结果。最终,即使表实际上包含新数据,查询也开始返回空结果。我观察到几个小时后查询确实提取了数据。我想知道为什么查询没有在表中实际可用时获取结果?
使用的工具
我的python程序是使用pyodbc库用Python3编写的,以连接到存储视图的REMOTE SQL Server 12。该视图从不断更新的表中获取数据。我的程序分为多个文件。该程序的一个模块产生一个线程进程,该进程生成一个包含两个变量的SQL查询字符串。其中一个变量是在启动线程之前计算的,而第二个变量是一个值,该值会不断更改SQL查询。
想法
这个想法是继续从表中提取事件号(不断添加新的事件号)。因此,线程每10分钟保持运行一次查询,以检查是否有新的事件号。 SQL查询包含一个WHERE条件,该条件表示拉出事件编号> last_pulled_event_number。该“ last_pulled_event_number”是根据查询返回的结果计算的。如果返回空结果,则该变量将保留其最后一个值。
问题
由于SQL Server中的视图不会每分钟更新一次,因此预计有时在查询运行时,不会添加任何新数据,因此结果将为空。在第一次执行时,查询返回正确的结果。随着循环的继续,预计第二次和第三次尝试均不会返回任何结果,但是在30分钟之后,至少有一个新行添加到该视图可以查看的表中。但是当我的查询在30分钟后运行时,它将获取空结果。
我尝试过的事情
我知道表和视图确实包含数据,因为我测试了这两种不同的方式。我的程序已经运行了6个小时,上次提取的事件数是3个小时。我打开SQL Server Studio,并使用相同的登录凭据运行完全相同的查询,它为我带来了新结果。然后,为确保SQL Server Studio没有执行任何操作,我复制了代码并运行了具有相同代码和相同查询的python程序。这次程序也返回了我预期的结果。在测试这两种方法时,我的程序已经运行了6个小时,完成了它的间隔,然后再次运行查询。但是,该程序没有结果,这是没有意义的。
同样,当我停止程序并重新启动它时。查询的行为符合预期,并获取新结果。
我正在使用python中的日志记录库进行调试。我注意到该程序最终确实会获取新结果,但是会长时间延迟获取它们。令我感到困惑的是,为什么当新运行的其他脚本或程序可以看到数据时,程序却看不到数据。是因为程序已运行6个小时或更长时间导致此问题吗?可能是因为多次执行完全相同的查询,所以将缓存的结果返回给我了吗?为什么系统不知道缓存结果不再有效?
对此有任何帮助,感激不尽!
# My code in the thread
while not self.shutdown_flag.is_set():
# SQL Query that pulls incident
sql_query = '''
select varc.EventNumber
from vw_Events varc (nolock)
where varc.CompanyNumber in (
''' + string_of_cust_numbers + '''
)
and varc.bCommented = 0
and varc.EventNumber > ''' + str(last_known_inc_number) + '''
and varc.InsertTimeStampGMT >= GETDATE() - 1 -- Need to look at the Added to Queue value rather than when the incident was generated
order by varc.EventNumber
'''
exec_msg = 'Querying the SQL Server database to fetch event numbers from live queue'
exception_msg = 'Queue Fetching Query Execution Failed!'
query_results = self.db_util.executeASQL(sql_cursor, sql_query, 'INFO', exec_msg, exception_msg)
if query_results is None:
logging.critical('Queue Fetcher query had some issue. Investigate. Terminating program')
return
else:
logging.info('Fetched Queue: {}'.format(query_results))
# Check if the query returned any results and then add to queue
if query_results:
for row in query_results:
my_queue.put(
int(row[0])) # Adds the first element which is going to be the incident number in the queue one by one
# TODO Need to add Queue size checks over here
# Update last incident number which will be used to fetch only the new incident numbers next time
if query_results: # This checks if the results list is empty
last_known_inc_number = query_results.pop()[0] # Last entry in results, First element in the tuple
# Constant Time Interval Gap - 1 minutes for now
logging.debug('Last Known Inc Number: {}'.format(last_known_inc_number))
logging.info('Sleeping for 10 minutes')
time.sleep(600)
# Custom SQL execute function defined in other file
def executeASQL(self, db_cursor, sql_query, loglevel, exec_msg, exception_msg):
'''
This function is a wrapper around ASQL execute query to make the code more readable
:param db_cursor: SQL Cursor object
:param sql_query: String - sql query to execute
:param loglevel: String - Logging level for execution message
:param exec_msg: String - Logging message during execution
:param exception_msg: String - Logging message if an exception arises
:return: Query results if succeeded else None
'''
try:
self.loglevel_dict.get(loglevel, 'DEBUG')(exec_msg)
db_cursor.execute(sql_query)
results = db_cursor.fetchall()
return results
except pyodbc.Error as err:
self.loglevel_dict.get(loglevel, 'EXCEPTION')(exception_msg)
# logging.exception('Execution of ASQL Query to determine SIP failed')
return None
实际结果 提取的队列日志显示一个空列表-> [] 即使视图确实具有数据,因为当我们使用另一个python程序运行相同的查询时,它也会返回结果
预期结果 提取的队列日志应提取新数据-> [1,2,3]