2017-08-16 108 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;