2017-08-16 102 views
0

要求:
一套仪表板显示在ERP主屏幕上。数据根据当前用户权限进行过滤。带SQL后端的高性能仪表板

截至目前: Home Dashboard

高图表用于数据可视化。后台网页在C#.NET

问题:

  • 每当用户改变它击中实时数据库并获取数据的过滤器。
  • 每天早上,用户几乎在同一时间登录,所以会有大量的请求发送到SQL服务器。这会导致性能问题。还有更多的图表来。

我们计划为数据实现SQL Analysis Dashboard Qubes。 有人可以建议,如果这是一个正确的方式或建议任何其他更好的方式。 更好的体系结构。

谢谢。

+1

恐怕这并不是那么简单的答案,即使与整个SO的经验在一起。您必须根据您拥有的预算,您店铺中已有的技术,预期的结果(比如报告数据需要可用于现场报告)以及您/您的团队在报告中的技能/ DW解决方案,是否有任何业务限制? –

+0

这么多因素。有多少用户?加载时间目前的影响是什么?什么是可接受的加载时间?等等有什么疑问 - 是否有很多处理将会放慢速度?不能说SQL Analysis Dashboard Qubes的有效性,但某些形式的预处理和/或缓存数据当然是一个方向。 – jlbriggs

+0

@BartoszX现在我们商店没有任何支持软件可以接受Highcharts。建议实时数据,如果不是几个小时的旧数据也很好。我是这份工作的主人。我真的是.net的初学者,在SQL方面有4年的经验。此外,我还聘请了高级数据库管理员来帮助我进行性能调优,并且他擅长DW解决方案(SSAS)。限制:转到具有不同服务器配置的客户端。有些非常好,有些非常糟糕。 –

回答

0

所以首先要做的事 - 你需要知道什么是真正的问题,如果资源 - 只需要添加更多,因为你需要它们,并尝试优化你的代码。但从我的经验来看,情况并非如此 - 我相信你有一个经典的行锁示例,而你有并发事务试图访问相同的数据。如果你有deadlocks的问题,你可能想尝试使用snapshot transaction isolation level,这只是并发读取,你可能想创建一个虚拟的replication,并将最重的访问对象复制到单独的只读数据库,如果你已经采取log backups使用log shipping并在可能的时候从副本中读取声音,以及对我的讨价还价。

如果你很乐意努力修复它,我会建议考虑一个Data Warehouse解决方案,并将你的应用程序/报告链接到它。

关于data cubes和/或SSAS的解决方案,这是有益的,但要做到这一点,你会发现你所需要的DW反正看到一个真正的优势来自它的客户将不得不以大量的维聚集的不只是一个简单的“刷新今天的数据下载报告”。

将会有很多工作给你,我建议分析等待状态作为一个起点,以了解你现在到底在哪里,什么是真正的问题。作为礼物,请找到下面的代码,以获得这些统计数据:

DECLARE @Wait_Types_Excluded TABLE([wait_type] nvarchar(60) PRIMARY KEY); 

INSERT INTO @Wait_Types_Excluded([wait_type]) VALUES 

(N'BROKER_EVENTHANDLER'), (N'BROKER_RECEIVE_WAITFOR'), (N'BROKER_TASK_STOP'), (N'BROKER_TO_FLUSH'), (N'BROKER_TRANSMITTER') 
,(N'CHECKPOINT_QUEUE'), (N'CHKPT'), (N'CLR_AUTO_EVENT'), (N'CLR_MANUAL_EVENT'), (N'CLR_SEMAPHORE') ,(N'DIRTY_PAGE_POLL') 
,(N'DISPATCHER_QUEUE_SEMAPHORE'), (N'EXECSYNC'), (N'FSAGENT'), (N'FT_IFTS_SCHEDULER_IDLE_WAIT'), (N'FT_IFTSHC_MUTEX') 
,(N'KSOURCE_WAKEUP'), (N'LAZYWRITER_SLEEP'), (N'LOGMGR_QUEUE'), (N'MEMORY_ALLOCATION_EXT'), (N'ONDEMAND_TASK_QUEUE') 
,(N'PREEMPTIVE_XE_GETTARGETSTATE'), (N'PWAIT_ALL_COMPONENTS_INITIALIZED'), (N'PWAIT_DIRECTLOGCONSUMER_GETNEXT') 
,(N'QDS_PERSIST_TASK_MAIN_LOOP_SLEEP'), (N'QDS_ASYNC_QUEUE'), (N'QDS_CLEANUP_STALE_QUERIES_TASK_MAIN_LOOP_SLEEP') 
,(N'QDS_SHUTDOWN_QUEUE'), (N'REDO_THREAD_PENDING_WORK'), (N'REQUEST_FOR_DEADLOCK_SEARCH'), (N'RESOURCE_QUEUE') 
,(N'SERVER_IDLE_CHECK'), (N'SLEEP_BPOOL_FLUSH'), (N'SLEEP_DBSTARTUP'), (N'SLEEP_DCOMSTARTUP'), (N'SLEEP_MASTERDBREADY') 
,(N'SLEEP_MASTERMDREADY'), (N'SLEEP_MASTERUPGRADED'), (N'SLEEP_MSDBSTARTUP'), (N'SLEEP_SYSTEMTASK'), (N'SLEEP_TASK') 
,(N'SLEEP_TEMPDBSTARTUP'), (N'SNI_HTTP_ACCEPT'), (N'SP_SERVER_DIAGNOSTICS_SLEEP'), (N'SQLTRACE_BUFFER_FLUSH') 
,(N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP'), (N'SQLTRACE_WAIT_ENTRIES'), (N'WAIT_FOR_RESULTS'), (N'WAITFOR') 
,(N'WAITFOR_TASKSHUTDOWN'), (N'WAIT_XTP_RECOVERY'), (N'WAIT_XTP_HOST_WAIT'), (N'WAIT_XTP_OFFLINE_CKPT_NEW_LOG') 
,(N'WAIT_XTP_CKPT_CLOSE'), (N'XE_DISPATCHER_JOIN'), (N'XE_DISPATCHER_WAIT'), (N'XE_TIMER_EVENT') 
,(N'DBMIRROR_DBM_EVENT'), (N'DBMIRROR_EVENTS_QUEUE'), (N'DBMIRROR_WORKER_QUEUE'), (N'DBMIRRORING_CMD'), 
(N'HADR_CLUSAPI_CALL'), (N'HADR_FILESTREAM_IOMGR_IOCOMPLETION'), (N'HADR_LOGCAPTURE_WAIT'), 
(N'HADR_NOTIFICATION_DEQUEUE'), (N'HADR_TIMER_TASK'), (N'HADR_WORK_QUEUE'); 

SELECT 
[Approx_Wait_Stats_Restart_Date] = CAST(DATEADD(minute, -CAST((CAST(ws.[wait_time_ms] as decimal(38,18))/60000.0) as int), SYSDATETIME()) as smalldatetime) 
,[SQL_Server_Last_Restart_Date] = CAST(si.[sqlserver_start_time] as smalldatetime) 
FROM sys.dm_os_wait_stats ws, sys.dm_os_sys_info si 
WHERE ws.[wait_type] = N'SQLTRACE_INCREMENTAL_FLUSH_SLEEP'; 

SELECT TOP 25 
ws.[wait_type] 
,[Total_Wait_(s)]   = CAST(SUM(ws.[wait_time_ms]) OVER (PARTITION BY ws.[wait_type])/1000.0 as decimal(19,3)) 
,[Resource_(s)]   = CAST(SUM([wait_time_ms] - [signal_wait_time_ms]) OVER (PARTITION BY ws.[wait_type])/1000.0 as decimal(19,3)) 
,[Signal_(s)]    = CAST(SUM(ws.[signal_wait_time_ms]) OVER (PARTITION BY ws.[wait_type])/1000.0 as decimal(19,3)) 
,[Avg_Total_Wait_(ms)] = CASE WHEN SUM(ws.[waiting_tasks_count]) OVER (PARTITION BY ws.[wait_type]) > 0 THEN SUM(ws.[wait_time_ms]) OVER (PARTITION BY ws.[wait_type])/ SUM(ws.[waiting_tasks_count])OVER (PARTITION BY ws.[wait_type]) END 
,[Avg_Resource_Wait_(ms) = CASE WHEN SUM(ws.[waiting_tasks_count]) OVER (PARTITION BY ws.[wait_type]) > 0 THEN SUM(ws.[wait_time_ms] - ws.[signal_wait_time_ms]) OVER (PARTITION BY ws.[wait_type])/ SUM(ws.[waiting_tasks_count]) OVER (PARTITION BY ws.[wait_type])END 
,[Avg_Signal_Wait_(ms)] = CASE WHEN SUM(ws.[waiting_tasks_count]) OVER (PARTITION BY ws.[wait_type])> 0 THEN SUM(ws.[signal_wait_time_ms]) OVER (PARTITION BY ws.[wait_type])/ SUM(ws.[waiting_tasks_count]) OVER (PARTITION BY ws.[wait_type])END 
,[Waiting_Tasks_QTY]  = SUM(ws.[waiting_tasks_count]) OVER (PARTITION BY ws.[wait_type]) 
,[Percent_of_Total_Waits_Time] = CAST(CAST(SUM(ws.[wait_time_ms]) OVER (PARTITION BY ws.[wait_type]) as decimal)/CAST(SUM(ws.[wait_time_ms]) OVER() as decimal) * 100.0 as decimal(5,2)) 
,[Percent_of_Total_Waits_QTY]  = CAST(CAST(SUM(ws.[waiting_tasks_count]) OVER (PARTITION BY ws.[wait_type]) as decimal)/ CAST(SUM(ws.[waiting_tasks_count]) OVER() as decimal) * 100.0 as decimal(5,2)) 
FROM sys.dm_os_wait_stats ws 
LEFT JOIN @Wait_Types_Excluded wte ON ws.[wait_type] = wte.[wait_type] 
WHERE wte.[wait_type] IS NULL 
AND ws.[waiting_tasks_count] > 0 
ORDER BY [Total_Wait_(s)] DESC;