英文:
Is it possible to alter my SQL code to make my SSRS report run faster?
问题
我是新手使用SSRS报表,试图提高我的SSRS报表的运行时间。如果我添加更多的筛选条件(在WHERE子句中),我可以让它运行。然而,目前报表运行一段时间然后超时。我需要的数据存储在三个不同的表中。
以下是我的代码:
SELECT DISTINCT
gl_detail.a_org
,gl_detail.a_object
,gl_master.a_object_desc
,ap_invoice.i_gl_eff_date
,gl_detail.j_jnl_source
,ap_invoice.a_vendor_number
,ap_vendor.a_vendor_name
,ap_invoice.a_purch_order_no
,ap_invoice.i_invoice_desc
,ap_invoice.a_check_number
,ap_invoice.a_line_item_amount
,ap_invoice.j_jrnl_entry_year
,ap_invoice.j_jrnl_entry_per
FROM
gl_detail
INNER JOIN ap_invoice
ON gl_detail.a_object = ap_invoice.a_object
INNER JOIN ap_vendor
ON ap_invoice.a_vendor_number = ap_vendor.a_vendor_number
INNER JOIN gl_master
ON ap_invoice.a_object = gl_master.a_object
WHERE
gl_detail.j_jnl_source = N'API'
AND gl_detail.a_org = N'10051401'
AND gl_detail.a_object >= N'50000'
AND gl_detail.a_object < N'60000'
AND ap_invoice.j_jrnl_entry_year = N'2023'
ORDER BY
gl_master.a_object_desc
,ap_invoice.j_jrnl_entry_year
,gl_detail.a_org
,gl_detail.a_object
,ap_invoice.i_gl_eff_date
,gl_detail.j_jnl_source
,ap_invoice.a_vendor_number
,ap_vendor.a_vendor_name
,ap_invoice.a_purch_order_no
,ap_invoice.i_invoice_desc
,ap_invoice.a_check_number
,ap_invoice.a_line_item_amount
,ap_invoice.j_jrnl_entry_per
我阅读了很多类似问题的详细信息,但要么解决方案对我无效,要么我不够熟练以实施它们。我尝试使用具有相同数据的不同表来连接,但没有一个可以加速报表。至少,我仍然需要链接三个不同的表来连接这些数据。我还尝试链接不同的变量,但要么数据返回不正确,要么为空。我添加了"order by"子句,尝试添加"declare"来声明变量,但始终收到错误消息。我找到了有关SQL Profiler和SQL Server Management Studio的信息,但我在公司没有访问权限,也无法在计算机上下载新软件。
我在"WHERE"子句中添加了三个额外的项,只是为了测试报表是否会运行。它花费大约60秒才返回一行数据。然而,我不希望在最终报表中包含这些筛选条件。查看截图
最初,我想要运行多年的报表并添加一个下拉参数来在运行时选择年份,但我取消了这个想法,并改为在WHERE子句中添加'2023'日期以缩小数据范围。
谢谢。
英文:
I'm new to SSRS reports and trying to speed up the run time of my SSRS report. If I add further filters (in the WHERE clause), I can get it to run. However; as is, the report runs for a while and then times out. The data I need is in three different tables.
Here is my code:
` `SELECT DISTINCT
gl_detail.a_org
,gl_detail.a_object
,gl_master.a_object_desc
,ap_invoice.i_gl_eff_date
,gl_detail.j_jnl_source
,ap_invoice.a_vendor_number
,ap_vendor.a_vendor_name
,ap_invoice.a_purch_order_no
,ap_invoice.i_invoice_desc
,ap_invoice.a_check_number
,ap_invoice.a_line_item_amount
,ap_invoice.j_jrnl_entry_year
,ap_invoice.j_jrnl_entry_per
FROM
gl_detail
INNER JOIN ap_invoice
ON gl_detail.a_object = ap_invoice.a_object
INNER JOIN ap_vendor
ON ap_invoice.a_vendor_number = ap_vendor.a_vendor_number
INNER JOIN gl_master
ON ap_invoice.a_object = gl_master.a_object
WHERE
gl_detail.j_jnl_source = N'API'
AND gl_detail.a_org = N'10051401'
AND gl_detail.a_object >= N'50000'
AND gl_detail.a_object < N'60000'
AND ap_invoice.j_jrnl_entry_year = N'2023'
ORDER BY
gl_master.a_object_desc
,ap_invoice.j_jrnl_entry_year
,gl_detail.a_org
,gl_detail.a_object
,ap_invoice.i_gl_eff_date
,gl_detail.j_jnl_source
,ap_invoice.a_vendor_number
,ap_vendor.a_vendor_name
,ap_invoice.a_purch_order_no
,ap_invoice.i_invoice_desc
,ap_invoice.a_check_number
,ap_invoice.a_line_item_amount
,ap_invoice.j_jrnl_entry_per
I read a lot of details about similar problems, but either the solutions didn't work for me, or I'm not skilled enough to implement them. I tried using different tables that had the same data to link, but none of them sped up the report. At a minimum, I would still need to link three different tables to link this data. I also tried linking different variables, but either the data came back incorrect or null. I added the "order by" clause, I tried adding "declare" to declare variables but kept receiving errors. I found information on the SQL Profiler and SQL Server Management Studio but I don't have access to those at my company and we can't download new software onto our computers.
I added three additional items in my "WHERE" clause just to test that the report would actually run. It took about sixty seconds to return one line of data. However, I do not want those filters in the final report. See screenshot
Initially wanted to run it for multiple years and add a drop down parameter to select the year at run time, but I removed that and changed it to adding the '2023' date in the WHERE clause to narrow down the data.
Thank you.
答案1
得分: 1
不是答案,只是故障排除的指南。
给定这条评论:我认为我需要"DISTINCT"组件,否则它会给我很多重复的数据行
很可能是你的连接不正确。你的连接使它做了太多的工作,连接了太多的行,然后你在去重之后又让它做了额外的工作。如果你能正确设置连接列并移除去重,性能将有大幅提升。
要排除连接问题,你需要打开 SSMS(假设这是 SQL Server)并运行以下代码来计算在 gl_detail 表中筛选出的行数:
SELECT COUNT(*) As RowsFoundd
FROM
gl_detail
WHERE
gl_detail.j_jnl_source = N'API'
AND gl_detail.a_org = N'10051401'
AND gl_detail.a_object >= N'50000'
AND gl_detail.a_object < N'60000'
现在加入第一个连接。你应该得到相同数量的行数:
SELECT COUNT(*) As RowsFound
FROM
gl_detail
INNER JOIN ap_invoice
ON gl_detail.a_object = ap_invoice.a_object
WHERE
gl_detail.j_jnl_source = N'API'
AND gl_detail.a_org = N'10051401'
AND gl_detail.a_object >= N'50000'
AND gl_detail.a_object < N'60000'
如果得到更多的行,那么这个连接是不正确的。你可能需要添加更多的列到这个连接条件中:
ON gl_detail.a_object = ap_invoice.a_object
如果得到相同数量的行,请继续添加连接,直到找出生成重复行的连接。同时请记住,仅仅运行去重操作可能会删除掉合法的记录。你的报告不会进行对账。
英文:
Not an answer, just a guide for troubleshooting.
Given this comment: I believe I need the "DISTINCT" component, otherwise it gives me many lines of duplicate data
Likely your joins are incorrect. Your joins are making it do too much work by joining too many rows, then you make it do extra work after on that with distinct. If you can get the join columns correct and remove distinct you'll have a large performance improvement
To troubleshoot your joins you need to open up SSMS (Assuming this is SQL Server) and run this to count the filtered rows in gl_detail
SELECT COUNT(*) As RowsFoundd
FROM
gl_detail
WHERE
gl_detail.j_jnl_source = N'API'
AND gl_detail.a_org = N'10051401'
AND gl_detail.a_object >= N'50000'
AND gl_detail.a_object < N'60000'
Now put your first join in. You should get the same number of rows.
SELECT COUNT(*) As RowsFound
FROM
gl_detail
INNER JOIN ap_invoice
ON gl_detail.a_object = ap_invoice.a_object
WHERE
gl_detail.j_jnl_source = N'API'
AND gl_detail.a_org = N'10051401'
AND gl_detail.a_object >= N'50000'
AND gl_detail.a_object < N'60000'
If you get a more rows, then this join is incorrect. You likely need to add more columns to this join
ON gl_detail.a_object = ap_invoice.a_object
If you get the same number of rows, keep adding joins until you work out what join is generating duplicates.
Also keep in mind just running distinct on this can drop out legitimate records. Your report is not going to reconcile.
答案2
得分: 0
以下是您要翻译的部分:
这不太像是一个答案,而更像是评论中的太多信息。
首先 - seanb的评论都是有效的。
其次 - 我假设这是SQL Server,因为您没有指定。
您需要分享更多细节。分享表模式和索引以及每个表的近似行数。要获取表和索引的脚本,请右键单击它们,然后执行“脚本表为 >> 创建到 >> 新查询窗口”等类似任务。
对于代码的一些评论。
在您的WHERE子句中,即使对于看起来是数字的列,您也在与Unicode字符串进行比较。
WHERE
gl_detail.j_jnl_source = N'API'
AND gl_detail.a_org = N'10051401'
AND gl_detail.a_object >= N'50000'
AND gl_detail.a_object < N'60000'
AND ap_invoice.j_jrnl_entry_year = N'2023'
如果这里的最后四列是数字的话,将其更改为以下内容将有所帮助
WHERE
gl_detail.j_jnl_source = N'API'
AND gl_detail.a_org = 10051401
AND gl_detail.a_object >= 50000
AND gl_detail.a_object < 60000
AND ap_invoice.j_jrnl_entry_year = 2023
因为当前查询需要将Unicode字符串(例如N'2023'
)隐式转换为数字,以便与表中的j_jrnl_entry_year
列进行比较。
接下来,这里使用DISTINCT
可能不是一个好主意,如果有两个相同的记录具有相同的金额,那么只会返回一个,我假设这是错误的。这也会稍微减慢速度。
接下来,如果这是作为数据集查询使用的,那么没有必要使用ORDER
子句,数据将根据您的行组和排序在报表中排序,因此将其包含在查询中只是浪费时间。
接下来,当您连接大表(也许它们不是大表,但值得一试)并将WHERE子句应用于多个表时,使用临时表通常可以提高性能。
下面是我重新构造的查询,包括上述所有更改。基本上,我从ap_invoice
表中提取了您所需的年份的数据,将结果放入了一个临时表中,然后连接到此表而不是原始表。您也可以对gl_detail表执行类似的任务,但我将其留给您。根据我的经验,这可能不会带来性能提升,但通常会有所帮助。
(我还将表名取了别名,因为这样更容易阅读)
-- 创建一个名为#inv的临时表,仅包含我们感兴趣的ap_invoive数据。
SELECT * INTO #inv FROM ap_invoice WHERE j_jrnl_entry_year = 2023
SELECT
gl.a_org
,gl.a_object
,m.a_object_desc
,i.i_gl_eff_date
,gl.j_jnl_source
,i.a_vendor_number
,v.a_vendor_name
,i.a_purch_order_no
,i.i_invoice_desc
,i.a_check_number
,i.a_line_item_amount
,i.j_jrnl_entry_year
,i.j_jrnl_entry_per
FROM gl_detail AS gl
INNER JOIN #inv AS i -- 使用上面创建的新的较小的发票表
ON gl.a_object = o.a_object
INNER JOIN ap_vendor AS v
ON o.a_vendor_number = v.a_vendor_number
INNER JOIN gl_master AS m
ON i.a_object = m.a_object
WHERE
gl.j_jnl_source = N'API'
AND gl.a_org = 10051401
AND gl.a_object >= 50000
AND gl.a_object < 60000
英文:
This is not an answer as much but too much info for a comment..
First - seanb's comments are all valid
Second - I'm assuming this is SQL Server as you have not specified
You would need to share more details. Share the table schemas and indexes and the approximate row counts for each. To get the table and indexes scripted out, right-click then and then do "Script Table As >> Create To >> New query window" and do a similar task for the indexes.
A few comments on the code.
In your WHERE clause you are comparing to unicode strings even for columns that appear to be numeric.
WHERE
gl_detail.j_jnl_source = N'API'
AND gl_detail.a_org = N'10051401'
AND gl_detail.a_object >= N'50000'
AND gl_detail.a_object < N'60000'
AND ap_invoice.j_jrnl_entry_year = N'2023'
If the last four columns here are numeric then changing it to this
WHERE
gl_detail.j_jnl_source = N'API'
AND gl_detail.a_org = 10051401
AND gl_detail.a_object >= 50000
AND gl_detail.a_object < 60000
AND ap_invoice.j_jrnl_entry_year = 2023
would help as currently the query is having to take the unicode string e.g. N'2023'
and implicitly convert it to a number in order to compare it to the j_jrnl_entry_year
column in the table.
Next, the DISTINCT
is probably a bad idea here, if you have two identical records with the same amounts, then only one would be returned which I assume would be wrong. This will also slow things down a little.
Next, if this is being used as a dataset query, then there is no need for the ORDER
clause, the data will be ordered in the report based on your rowgroups and sorting so it's just a waste of time putting it in the query.
Next, using temp tables can often increase performance when you are joining larges tables (maybe they are not large but this is worth trying) and applying the WHERE clause to more than one table.
Below I've restructured the query including all the above changes. Basically what I have done is grabbed the data from the ap_invoice
table just for the year you need, put the results into a temp table and then joined to this rather than the original table. You could do a simialr task on thegl_detail table too but I'll leave that to you. This may not give any performance increase, but it often does in my experience.
(I've also aliased the table names below as it makes the whole thing easier to read)
-- create a temp table called #inv containing only the ap_invoive data we are interested in.
SELECT * INTO #inv FROM ap_invoice WHERE j_jrnl_entry_year = 2023
SELECT
gl.a_org
,gl.a_object
,m.a_object_desc
,i.i_gl_eff_date
,gl.j_jnl_source
,i.a_vendor_number
,v.a_vendor_name
,i.a_purch_order_no
,i.i_invoice_desc
,i.a_check_number
,i.a_line_item_amount
,i.j_jrnl_entry_year
,i.j_jrnl_entry_per
FROM gl_detail AS gl
INNER JOIN #inv AS i -- use the new, smaller invoice table created above
ON gl.a_object = o.a_object
INNER JOIN ap_vendor AS v
ON o.a_vendor_number = v.a_vendor_number
INNER JOIN gl_master AS m
ON i.a_object = m.a_object
WHERE
gl.j_jnl_source = N'API'
AND gl.a_org = 10051401
AND gl.a_object >= 50000
AND gl.a_object < 60000
答案3
得分: 0
通过从不同的表中选择数据并正确连接它们,我能够立即获取我报告所需的数据。我在运行时添加了一个参数来选择年份。
SELECT DISTINCT
gl_history.a_org
,gl_history.a_object
,gl_history.h_effective_date
,gl_history.j_jnl_source
,gl_history.h_ref1_vendor
,gl_history.h_ref2_po_no
,gl_history.h_line_comment
,gl_history.h_gross_amount
,gl_history.h_transact_year
,ap_invoice.a_invoice_number
,gl_master.a_object_desc
,ap_invoice.a_check_number
,ap_vendor.a_vendor_name
,gl_history.j_jnl_line_id
FROM
gl_history
INNER JOIN ap_invoice
ON gl_history.h_ref3_invoice_no = ap_invoice.a_invoice_number AND gl_history.a_org = ap_invoice.a_org
INNER JOIN ap_vendor
ON ap_invoice.a_vendor_number = ap_vendor.a_vendor_number
INNER JOIN gl_master
ON gl_master.a_object = gl_history.a_object AND gl_master.a_org = gl_history.a_org
WHERE
gl_history.a_org = N'10051401'
AND gl_history.a_object >= N'50000'
AND gl_history.a_object < N'60000'
AND gl_history.j_jnl_source = N'API'
希望这对你有所帮助。
英文:
By selecting data from different tables and joining them properly, I was able to get the data that I need for my report to run almost instantly.I added a parameter to select the year at run time.
SELECT DISTINCT
gl_history.a_org
,gl_history.a_object
,gl_history.h_effective_date
,gl_history.j_jnl_source
,gl_history.h_ref1_vendor
,gl_history.h_ref2_po_no
,gl_history.h_line_comment
,gl_history.h_gross_amount
,gl_history.h_transact_year
,ap_invoice.a_invoice_number
,gl_master.a_object_desc
,ap_invoice.a_check_number
,ap_vendor.a_vendor_name
,gl_history.j_jnl_line_id
FROM
gl_history
INNER JOIN ap_invoice
ON gl_history.h_ref3_invoice_no = ap_invoice.a_invoice_number AND gl_history.a_org = ap_invoice.a_org
INNER JOIN ap_vendor
ON ap_invoice.a_vendor_number = ap_vendor.a_vendor_number
INNER JOIN gl_master
ON gl_master.a_object = gl_history.a_object AND gl_master.a_org = gl_history.a_org
WHERE
gl_history.a_org = N'10051401'
AND gl_history.a_object >= N'50000'
AND gl_history.a_object < N'60000'
AND gl_history.j_jnl_source = N'API'
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论