-
Notifications
You must be signed in to change notification settings - Fork 99
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory leak when selecting a large table #29
Comments
Thanks for the report! Could you please provide the definitions for your foreign server and foreign table? I think I may know the cause. I started using MemoryContexts in tds_fdw 1.0.3. Now that PostgreSQL is no longer auto-cleaning tds_fdw's memory, I may have to reset the MemoryContext when the query is complete. That reset should probably happen in tdsEndForeignScan(). Unfortunately, I'm not at home right now, which is where my tds_fdw development environment is set up. I probably won't have an opportunity to work on this for a week or so. |
Geoff, thanks for the amazingly quick reply! I'll test it now. |
Here is the table definition, though I've changed the column names just in case my employer would prefer that. CREATE TABLE api.orders |
The foreign table has the same columns, but it also has SERVER server |
I don't know if it's relevant, but the PostgreSQL server being inserted into is a master with streaming replication to one slave. Unfortunately, 780060b doesn't fix the problem. It's not important for this to be fixed over the weekend. Thanks again, Geoff! |
Rather than this being a memory leak, I wonder if I'm just using a very inefficient method to store Right now, I see that Even the PostgreSQL documentation says:
So I guess I should look into that as a possible fix when I get a chance. |
That'd be great. I was honestly surprised when I found out my problem was due to OOM, since the table can in principle fit in memory. On disk it's 18.6 GB. |
I will try 1.0.2 on Monday and see if that resolves the memory problem. |
Thanks! By the way, when you tried the most recent commit, did you restart the PostgreSQL server after doing |
Yup, I definitely restarted PostgreSQL. Sent from my phone
|
I tried 1.0.2 this morning. Memory usage went up while the query ran, but much more slowly. It finished successfully. So if 1.0.2 has a memory leak, it's much better than 1.0.3. |
Thanks for running the test! Since 1.0.2 performs better, it probably is related to the MemoryContext somehow. I'll let you know when I might have a fix. |
I think it would be useful to see how much memory The latest commit adds a few new variables:
Commit: 03879e3 Would you be willing to create a smaller copy of your table (maybe 100 rows or so?), and then could you use these variables to show how your memory usage grows? e.g. first set the variables, and execute the query:
And then your PostgreSQL log should have data that looks like this:
The |
Same issue, eats up unreasonable amount of memory compared to 1.0.1 |
This problem has bitten us, and when we downgrade to 1.0.2 we get bitten by the empty/null string problem that was fixed in the same commit that introduced memory contexts. Is this issue being worked on now? Would the kind of debugging data that you requested back on July 3 still be helpful? I tried playing with the code, but I'm new to memory contexts so progress was slow. |
Sorry to hear that this bug is causing you problems. I would like to fix this bug, but I haven't had the time to work on tds_fdw recently. Any information that you could provide would be great. I'm guessing that moving |
As a quick and dirty attempt, I just committed some changes that may fix the leak, but it still need to be tested. Can you try out the commit to see how things work for you? This changes in this commit cause the C-String array used for a row's values to be freed after the row is built with ExecStoreTuple. I'm not really sure if this is allowed by PostgreSQL's API. |
This new commit is better, but there is still a leak, to the point where I couldn't transfer a table of 160 million rows, 80 bytes per row (about 13 GB). The columns are fixed length - int, float or datetime. I created a table of 100 rows and 2 columns (int and float), and logged the stats that you mentioned with both commits fd5b441 and 2b09f99. Here are the logs: https://gist.github.com/tskenb/223b5bd3d3b2b772c255 |
…frees memory when it's cleaning up
Thanks for the logs! I can definitely tell that there is a big difference in memory usage before and after the patch. Before the patch, tds_fdw was using 243,408 blocks at query end. After the patch, tds_fdw was using 32,144 blocks. I just submitted a new commit: Can you please try that commit to see if that's better for you? By the way, if you are trying to transfer 13 GB, how much total memory does the system have? Also, what is |
The machine has 32 GB memory, and The latest commit is a further improvement, but there is still a leak and I still can't transfer that table. The new log is here: https://gist.github.com/tskenb/ca320fb3abdf06602e22 Thanks for your efforts so far. I'll see if I can work on it a bit too. |
…ntext in tdsGetColumnMetadata to prevent too much bloating over the iterations of tdsIterateForeignScan
After reading this, it sounds like memory contexts don't necessarily shrink when data is freed. I tried something a bit more aggressive. I changed Can you please try the latest commit? |
Interesting. The log file is here. On one hand, I can transfer the whole file and the memory pattern looks more like 1.0.2 - meaning it doesn't seem to grow with number of rows. And the resulting table looks close enough to correct that the diffs are probably due to other issues. On the other hand, that log file has some strange numbers in it and the solution is awfully hacky. I have been looking at it, but have so far only succeeded in making things worse. In the latest commit, it looks like stuff allocated in tdsIterateForeignScan doesn't use the "tds_fdw data" context at all. What was the original motivation for introducing a new memory context? Does some data need to be preserved across iterations? |
Awesome! That's great news!
If any differences point towards any more issues in If any differences are related to character encodings, then keep in mind that character encodings can be kind of tricky, since you have several different encodings with
While the solution sounds a bit strange, I'm not so sure that it's hacky. After thinking about it, this might be a better way to use PostgreSQL's API. (more on that next)
The reason for introducing the memory context was that I wanted to preserve column metadata between iterations of I didn't think that would be a problem, as long as I freed the memory that didn't need to persist at the end of a given iteration. That didn't quite work out as I expected because when the memory was freed, it seems that the memory context doesn't necessarily shrink. Also, even after freeing all of the memory that I allocated (except the column metadata), memory usage still seemed to grow too much for you. That makes me wonder if using the memory context in that way was unintentionally causing other data to be included in it when I called various PostgreSQL API functions that may make their own I'm still relatively new to PostgreSQL extension development, but I think this most recent commit is probably using the memory context in a more efficient way. It seems that different memory contexts should be used for persistent data and short-lived data. |
Thanks for the explanation. I agree now that the latest commit is good. I just have one tweak: I tried reverting the previous two commits - using Yeah, I think my diffs are not real diffs, just variances in representation. Thanks again for your help. |
…hat it pfrees memory when it's cleaning up" This reverts commit 8f15569.
Good catch! I've reverted those two commits.
No problem! I'm glad you are finding It might be time for a new release soon now that this memory issue appears to be under control. |
Fixed in v1.0.4. |
I have a large table in sql server 2008 r2, 57,731,898 rows by 35 columns. The following query causes my PostgreSQL service to crash because the server runs out of memory. The server is running CentOS 7 x64, PostgreSQL 9.4.4, tds_fdw 1.0.3, FreeTDS 0.95, and 256 GB of RAM.
Orders is a native table with the same columns as the tds_fdw-backed foreign table, foreign_orders.
insert into orders
select *
from foreign_orders
The text was updated successfully, but these errors were encountered: