We are currently using ReportViewer control embedded in an aspx file to render RDLC files for an MVC Web Application. The data is fetched from an SQL Server using nhibernate, the ReportViewer is running in Local Processing mode. The various reports contain calculations within the RDLC including sums, counts and grouping.
We are finding the reports using this method run terribly slowly, usually causing the web server to display the Service 'Unavailable Error'.
It appears that the live servers do not have enough resources to run these reports, and even in an environment where the servers have much more memory and CPU speed, while the reports do not time out, they take a very long time to render even a single report.
Does anyone have recommendations on this matter. How can we reduce the amount of processing time for these reports?
From observing the resource usage, the calculations carried out internally by report viewer on the data are taking a great deal of time. As an example of the data we are looking at about 3000 individual reports, using over 40000 records to calculate from.
Related
I am new to reporting in asp.net and can't get the things work up good for me.
Basically, I made a demo of what was told here. Everything worked fine and it generated report on my local system. But, did not worked on the web server.
Now, I've got a confusion here: There are 2 modes of a reporting in asp.net [VS 2010 - .NET 4.0], Local Mode and Server Mode. Local Mode has RDLC extension and Server mode has RDL as extension for the report design file, and it requires Sql Server reporting for support, for which on the other hand RDLC is made on the Client Machine [it may look to be a dumb question but, is it my machine or my pc and not the web server, means I cannot deploy and use it on the web server].
The base of the confusion is that I had uploaded the same demo project on my web hosting and ran it. The report Viewer control was showing perfectly and every thing was looking fine, but the actual report that was to be rendered was absent from below of the Report Viewer Toolbar. But, at the same time, I was able to download the PDF, XLS, and DOC format of the report completely fine, with the actual rows and columns generated, which shows that the report was being generated (A bar graph was also included in the design of rdlc, and it generated as well). I guess this was because the web-server did not had Report Viewer libraries installed on it, and did not know how to render the RDLC file.
So, here are the actual questions:
Am I correct in the thinking that a report can be generated on the webserver when you have RDLC as the report file format?Or should I use the RDL instead?
If I deploy my application with RDLC (Local Report), of-course on the web server, will it work fine? Is it possible to install or get the report viewer installed on the web server
And when should I use an RDLC and RDL and when not. A previous question When to use RDLC over RDL reports?., but I am looking for a simpler explanation in my scenario.
RDLC
Its client side reporting, Reports are shipped with the applications like windows app or web app.
Limited functionality in terms of formats in which the Report could be exported.
Report's data processing and rendering consumes address space of application in which Reports are hosted, it could be windows or web. This could cause performance issues if you pull huge reports often.
This does not require any separate SQL instance or licence.
RDL
This is server side reporting, reports are processed at dedicated server process called SQL Reporting Services' service and output is fed to applications or end users.
Server reporting is designed to perform and scale.
Runs as a separate process/service and requires SQL License.
Provides export to multiple formats not available in RDLC
Server reporting is extensible product. You can include your own data processing, security or delivery extensions.
It supports automated email delivery and file delivery of reports using Subscriptions out of the box.
Summary
Consider client side reporting (rdlc) if you are going to use simple and smaller reports not very often.
Consider (rdl) if you want to setup dedicated and central service to cater your Reporting requirements for various application users. This could be extended, monitored, optimized and scaled out on demand.
RDL and RDLC formats have the same XML schema. However, in RDLC files, some values (such as query text) are allowed to be empty, which means that they are not immediately ready to be published to a Report Server. The missing values can be entered by opening the RDLC file using the SQL Server 2008 version of Report Designer. (You have to rename .rdlc to .rdl first.)
RDL files are fully compatible with the ReportViewer control runtime. However, RDL files do not contain some information that the design-time of the ReportViewer control depends on for automatically generating data-binding code. By manually binding data, RDL files can be used in the ReportViewer control.
Note: that the ReportViewer control does not contain any logic for connecting to databases or executing queries. By separating out such logic, the ReportViewer has been made compatible with all data sources, including non-database data sources. However this means that when an RDL file is used by the ReportViewer control, the SQL related information in the RDL file is simply ignored by the control. It is the host application's responsibility to connect to databases, execute queries and supply data to the ReportViewer control in the form of ADO.NET DataTables.
Reference: http://forums.asp.net/t/1173578.aspx/1
Also check: http://dinesql.blogspot.com/2010/11/reporting-services-difference-between.html
I am using crystal reports in my application that is window based in C# for printing sale invoices and bills but the problem is that it takes some long time to proceed , I need some real time and fast method for this purpose please suggest some solution.
I link my crystal report by a procedure from database, is any alternative for printing invoice rather than crystal reports...
Crystal is "fast" if you take the time to learn what makes her happy. In my experience, the actual printing can account for most of the processing time. It may only take 25ms to create the .rpt file, but then 5000ms negotiating with a printer server. I have spent weeks wrestling with Crystal server-side printing.
It makes a BIG difference:
How you are printing : ReportDoc.PrintToPrinter vs. PrintOutputController.PrintReport
Whether the selected printer uses the same driver as the printer you used to develop the report.
Whether the printer is installed on the server (or just on a remote printer server) and whether it's installed in the profile of the IIS_Identity.
If you are configured incorrectly it can take 1 - 2 minutes to print a report (based on first hand experience). Make a few tweaks and you are suddenly < 50ms.
For instance, if you are using PrintToPrinter() and the specified printer is not in the list of .NET installed printers for the IIS user, it will take a long time to print. Install the printer so it's available to the IIS user, and bam, printing is instantaneous.
I faced an issue in one winforms project where the report was taking a long time to load but it was only for the first time. Later when reports were run, they had no issues at all.
We assumed that time was taken by framework to load crystal assemblies in memory.
So I created a hack that whenever application is run, I loaded an empty report in a background thread.
I have a report that is 68,000 pages plus that needs to be generated in PDF. (I put the comma in so you knew it wasn’t a typo :)
And this actually works fine if I generate it through the Website/WebService of SSRS.
It takes a little over a minute and generates the first page. During this time Server CPU goes to 100% and Memory to 2GB. After the first page is generated both CPU and Memory drop down to their pre-report state. Now if I choose to export to PDF. CPU on the Server goes to 100 but Memory does not jump significantly maybe .05GB (50 MB) as the pdf is being generated. This takes about 10-15 Minutes.
Now if I use the Render method in code
rs.Render(Me.ReportName, Me.ContentType, Nothing, Nothing, ....
I set the rs.Timeout to 1800000 //(30 minutes). CPU and Memory on the server spikes and about after 10 Minutes I get a out of Memory Exception. I believe from the server and not the host machine with the calling code (a web service).
Now I did notice when the PDF gets render through the SSRS website it creates a new URL with the parameters
ReportSession=gvrjxt4504wtpkiydu0o51fo
ControlID=5754f0889fb34bea80e7b5e97c120cfd
Culture=1033
UICulture=9
ReportStack=1
OpType=Export
FileName=Invoice+Session+Register+Batch
ContentDisposition=OnlyHtmlInline
Format=PDF
Now it is my belief that it is this ReportSession or ControlId that makes the PDF generation not take up so much memory.
Either way my question is how can I mimic through code the behavior that the Website is showing?
I about to look into LoadReport method and also NULL is one of the content types you can pass to the render method. But I cannot find an example nor and explanation of what it does.
So before I go down all these rabbit holes, has anyone else done something like this or encounter a project like this?
Background:If I generate the report one page at a time it took 9.5 hours to run and generate all the PDFs. I was really excited when I could generate the whole report in 10 minutes and use PDFSharp to split the report. Now I most likely can generate 10,000 or 20,000 at a time but it really fustrates me when a method works but I cannot duplicate it in code.
Maybe not specific to reports but still...
In my asp.net mvc web application there's a section for reports that show 5 columns of data that map almost directly to a table in the db.
The problem is, in some cases, the length of that report may exceed 40,000 records (I know, nobody can really process 40,000 records of data but the report is what it is) and as you can expect, it times out and throws an error.
The question is, what's a good way to process and deliver a report of that size? I thought about creating a small little console app that would build the report outside of the webserver but I'm kind of at a loss as to what direction to look into?
Does the report need to have up-to-the-minute data? If not, you can look at generating the report as a PDF at night (or whenever your server isn't busy) and just providing a link to the PDF. A scheduled task that runs a console app as you suggested could create the report and output it to a file. A lot of reporting tools like Crystal Reports will allow you to export the report to a PDF or an Excel spreadsheet. For that matter, you could generate the report on a completely different machine and then copy it over to the web server. This could allow you to update the report every hour (or whatever) without putting such a load on your web server.
Generating the report while the user waits is probably not a good idea (not to mention SQL / IIS timeouts etc)
You could get the user request a report, then have a windows service pick up these requests, generate the report and email the user? (or have some kind of ajax polling script on the site to notify users when their reports are ready?)
You could extend this to scheduling of the same report at recurring intervals etc.
I would look into SQL Reporting Services (assuming this is running on SQL Server). There's several delivery options which may be better suited to your application's needs (you can schedule a PDF or Excel document to show up in someone's mailbox every night, for example).
There's also a great article from the StackOverflow team that allows background processes within ASP.NET if you can simply generate this report every so often instead of on-demand (maybe every 5-10 minutes?)
https://blog.stackoverflow.com/2008/07/easy-background-tasks-in-aspnet/
Another frequent usage I've seen to handle large scale reporting is setting up a windows service that does the physical generation of the report which dumps the completed binary into a database or file store somewhere and then updates data to show the report is complete with the information needed for the application to link the completed report.
Then you could have your do report button fire off a request to initiate a report and then move them to a processing report page where it lists all the reports queued up / processing for them.
It's doubtful that a user would ever actually look at all of a 40,000 row report. So why not show just the top 1,000 most current rows ordered backwards? If you're using a reporting solution that supports on-demand reports, you could always drill down to second report that shows the next 1,000 most current rows. Just a thought...
I am working on a ASP.net application written in C# with Sql Server 2000 database. We have several PDF reports which clients use for their business needs. The problem is these reports take a while to generate (> 3 minutes). What usually ends up happening is when the user requests the report the request timeout kills the request before the web server has time to finish generating the report, so the user never gets a chance to download the file. Then the user will refresh the page and try again, which starts the entire report generation process over and still ends up timing out. (No we aren't caching reports right now; that is something I am pushing hard for...).
How do you handle these scenarios? I have an idea in my head which involves making an aysnchronous request to start the report generating and then have some javascript to periodically check the status. Once the status indicates the report is finished then make a separate request for the actual file.
Is there a simpler way that I am not seeing?
Using the filesystem here is probably a good bet. Have a request that immediately returns a url to the report pdf location. Your server can then either kick off an external process or send a request to itself to perform the reporting. The client can poll the server (using http HEAD) for the PDF at the supplied url. If you make the filename of the PDF derive from the report parameters, either by using a hash or directly putting the parameters into the name you will get instant server side caching too.
I would consider making this report somehow a little bit more offline from the processing point of view.
Like creating a queue to put report requests into, process the reports from there and after finish, it can send a message to the user.
Maybe I would even create a separate Windows Service for the queue handling.
Update: sending to the user can be email or they can have a 'reports' page, where they can check their reports' status and download them if they are ready.
What about emailing the report to the user. All the asp page should do is send the request to generate the report and return a message that the report will be emailed after is has finished running.
Your users may not accept this approach, but:
When they request a report (by clicking a button or a link or whatever), you could start the report generation process on a separate thread, and re-direct the user to a page that says "thank you, your report will be emailed to you in a few minutes".
When the thread is done generating the report, you could email the PDF directly (probably won't work because of size), or save the report on the server and email a link to the user.
Alternatively, you could go into IIS and raise the timeout to > 3 minutes.
Here is some of the things I would do if I would be presented this problem:
1- Stop those timeout! They are a total waste of resources. (bring up the timeout value of asp pages)
2- Centralize all the db access in one single point, then gather stats about what reports ran when by whom and how much time it took. Investigate why it takes so long, is it because of report complexity? data range? server load? (you could actually all write that on a .csv file on the server and import this file periodically in the sql server to analyze later).
Eventually, it's going to be easier for you to "cache" reports if you go through this single access point (example, same query same date will return same PDF previously generated)
3- I know this really wasn't the question but have you tried diving into those queries to see why they are so long to run? Query tuning maybe?
4- Email/SMS/on screen message when report is ready seems great... if your user generally send a batch of report to be generated maybe a little dashboard indicating progression of "their" queue could be built in the app. A little ajax control would periodically refresh the status..
Hint: If you used that central db access and you have sufficient information about what runs when why and how-long you will eventually be able to roughly estimates the time it will take for a report to run.
If the response time is mission critical, should certain users be limited in the data range (date range for example) during some hours of the day?
Good luck and please post more details about your scenario if you want to get more accurate hints...
Query tuning is probably your best place to start. Though I don't know you are generating the report, that step shouldn't really take all that long. A poorly performing query on the other hand could absolutely kill your performance.
Depending on what you find in looking at the query, you may need to add some indexes, or possibly even set up a table to store the information for your report in a denormalized way, to make it available faster. This denormalized table could then be refreshed (through a SQL Server Job) every hour, or with whatever frequency your requirements dictate (within reason).
If its' a relatively static report, without varying user input parameters, then caching the report run earlier in the day would be a good idea as well, but its' hard to say any more about this without knowing your situation.
For a problem like this you really need to start at the database unless you have reason to suspect your report generating code of being the culprit. There are various band-aids you could use that might help for a while, but if your db is the root cause then those solutions will not scale well, and you'll likely run into similar problems (or worse) some time in the future.