How does Scylla Evict Data from its Cache? - database

How does Scylla determine when to evict data from its cache? For example, suppose table T has the following structure:
K1 C1 V1 V2 V3
I populate the above table with 500 rows (e.g, the query SELECT * from T WHERE K1 = X & C1 = Y returns 500 rows).
Some time later I insert a new row into the above table that would cause the above query to return 501 rows, instead of 500 rows.
Does Scylla know to automatically evict the 500 rows from its cache or at least to add row 501 to its cache? If not, most queries will quickly start returning outdated data. Similarly, what happens if I don’t add a new row to the database, rather I update one of the existing 500 rows. Is Scylla aware of this modification and capable of updating its cache automatically? If yes, is it smart enough only to update the data that changed (the new row or the row that was modified) or does it evict/update all 500 rows?
Are there any cases to be aware of where data is updated in SSTables but not in memory?
Thanks
P.S
I read a lot about how caching works in Scylla but I didn’t see a clear answer to the above question. If Scylla is indeed aware of background updates I would also be curious to learn HOW it achieves such dynamic and intelligent updating of its cache.

I think you are misunderstanding what the cache does in Scylla, or any database for that matter.
The row cache, as its name suggests, caches (i.e., keeps in memory) individual rows - not the results of entire requests. So the fact that a request at one point returned 500 rows does not mean that the next time this request will come Scylla will return the same 500 rows. Not at all. Let me try to explain what does happen, although this is also documented elsewhere and I'll also simplify some details to hopefully get the point across:
When a Scylla node boots up, all the data is located on disk (stored in files known as sstables) and nothing is in memory. When a user asks to read one specific row that is not already in the in-memory cache, this row is read from disk and then stored in the cache. If the user later reads the same row again, it is returned from cache immediately. If the user writes to this row, the row is updated in the cache as well as on disk (the details are slightly more complicated, there is also an in-memory table - memtable - but I'm trying to simplify). The cache is always up-to-date - if a row appears in it, it is correct. Of course it also may not appear in it.
The situation you describe in your question's text (although not the actual query you posted!) is about a scan of a slice of a partition, returning not one but many rows (500 or 501). Scylla needs to (and does) put in a bit more work to handle this case correctly:
When the scan of a certain range is done for the first time, Scylla reads those 500 rows in that range, and puts each of them in the row cache. But it also remembers that the cache is contiguous in that range - these 500 rows are everything that exists in this range. So when the user tries the same query again, the cache doesn't need to check if maybe there are additional rows between those 500 - it knows there aren't. If you later write a 501st row inside this range, this row is added to the cache, which knows it remained contiguous, so the next scan of this range will return 501 rows. Scylla does not need to evict the 500 rows just because one was added to the same partition.
If at some later point in time Scylla runs out of memory and needs to evict some rows from the cache, it may decide to evict all these 501 rows from the cache - or some of them. If it evicts some of them, it loses continuity - if it only remembers, say, 400 rows for the original range, if the user asks to scan that range again Scylla is forced (again, simplifying some details) to read all the rows in the range from disk, because it has no idea which specific rows it is missing in this range.

Related

Why PostgreSQL(timescaledb) costs more storage in table?

I'm new to database. Recently I start using timescaledb, which is an extension in PostgreSQL, so I guess this is also PostgreSQL related.
I observed a strange behavior. I calculated my table structure, 1 timestamp, 2 double, so totally 24bytes per row. And I imported (by psycopg2 copy_from) 2,750,182 rows from csv file. I manually calculated the size should be 63MB, but I query timescaledb, it tells me the table size is 137MB, index size is 100MB and total 237MB. I was expecting that the table size should equal my calculation, but it doesn't. Any idea?
There are two basic reasons your table is bigger than you expect:
1. Per tuple overhead in Postgres
2. Index size
Per tuple overhead: An answer to a related question goes into detail that I won't repeat here but basically Postgres uses 23 (+padding) bytes per row for various internal things, mostly multi-version concurrency control (MVCC) management (Bruce Momjian has some good intros if you want more info). Which gets you pretty darn close to the 137 MB you are seeing. The rest might be because of either the fill factor setting of the table or if there are any dead rows still included in the table from say a previous insert and subsequent delete.
Index Size: Unlike some other DBMSs Postgres does not organize its tables on disk around an index, unless you manually cluster the table on an index, and even then it will not maintain the clustering over time (see https://www.postgresql.org/docs/10/static/sql-cluster.html). Rather it keeps its indices separately, which is why there is extra space for your index. If on-disk size is really important to you and you aren't using your index for, say, uniqueness constraint enforcement, you might consider a BRIN index, especially if your data is going in with some ordering (see https://www.postgresql.org/docs/10/static/brin-intro.html).

What is the threshold for ALL_ROWS flag of DBMS_CHANGE_NOTIFICATION?

I am trying to create a cache for a table in Oracle DB. I monitor the changes in the DB using DBMS_CHANGE_NOTIFICATION to automatically update the cache.
This is however only working in a satisfactory manner as long as the updates I do are rather small -- if I delete large portion of rows, the ALL_ROWS flag of the notification structure is set to true and the array of ROWIDs is NULL.
By trial and error I found out that the threshold for number of updated rows is about 100 rows which is really too little. If a table contains several million rows and I delete a thousand I do not get information on what was updated and I have to refresh the cache for the whole table which is unacceptable.
Can I somehow change this threshold? I could not find a specific answer in documentation:
If the ALL_ROWS (0x1) bit is set it means that either the entire table
is modified (for example, DELETE * FROM t) or row level granularity of
information is not requested or not available in the notification and
the receiver has to conservatively assume that the entire table has
been invalidated.
This only gives me vague information.
From the docs I found this:
If the ALL_ROWS bit is set in the table operation flag, then it means
that all rows within the table may have been potentially modified. In
addition to operations like TRUNCATE that affect all rows in the
tables, this bit may also be set if individual rowids have been rolled
up into a FULL table invalidation.
This can occur if too many rows were modified on a given table in a
single transaction (more than 80) or the total shared memory
consumption due to rowids on the RDBMS is determined too large
(exceeds 1 % of the dynamic shared pool size). In this case, the
recipient must conservatively assume that the entire table has been
invalidated and the callback/application must be able to handle this
condition.
I rolled by own solution years ago, which gives me control/flexibility, but perhaps someone has a workaround for you (commit in small chunks of 50? but what if your app isn't the only one changing the table?). I think the whole point is to only cache tables that are slowly changing, but this restriction does seem silly to me.
Currently there is a procedure where you can specify the value:
SET_ROWID_THRESHOLD
It would be nice if I could look up what the current value is with a getter, I haven't found it.

Are table-scan results held in memory negating the benefit of indexes?

Theoretical SQL Server 2008 question:
If a table-scan is performed on SQL Server with a significant amount of 'free' memory, will the results of that table scan be held in memory, thereby negating the efficiencies that may be introduced by an index on the table?
Update 1: The tables in question contain reference data with approx. 100 - 200 records per table (I do not know the average size of each row), so we are not talking about massive tables here.
I have spoken to the client about introducing a memcached / AppFabric Cache solution for this reference data, however that is out of scope at the moment and they are looking for a 'quick win' that is minimal risk.
Every page read in the scan will be read into the buffer pool and only released under memory pressure as per the cache eviction policy.
Not sure why you think that would negate the efficiencies that may be introduced by an index on the table though.
An index likely means that many fewer pages need to be read and even if all pages are already in cache so no physical reads are required reducing the number of logical reads is a good thing. Logical reads are not free. They still have overhead for locking and reading the pages.
Besides the performance problem (even when all pages are in memory a scan is still going to be many many times slower than an index seek on any table of significant size) there is an additional issue: contention.
The problem with scans is that any operation will have to visit every row. This means that any select will block behind any insert/update/delete (since is guaranteed to visit the row locked by these operations). The effect is basically serialization of operations and adds huge latency, as SELECT now have to wait for DML to commit every time. Even under mild concurrency the effect is an overall sluggish and slow to respond table. With indexes present operations are only looking at rows in the ranges of interest and this, by virtue of simple probabilities, reduces the chances of conflict. The result is a much livelier, responsive, low latency system.
Full Table Scans also are not scalable as the data grows. It’s very simple. As more data is added to a table, full table scans must process more data to complete and therefore they will take longer. Also, they will produce more Disk and Memory requests, further putting strain on your equipment.
Consider a 1,000,000 row table that a full table scan is performed on. SQL Server reads data in the form of an 8K data page. Although the amount of data stored within each page can vary, let’s assume that on average 50 rows of data fit in each of these 8K pages for our example. In order to perform a full scan of the data to read every row, 20,000 disk reads (1,000,000 rows / 50 rows per page). That would equate to 156MB of data that has to be processed, just for this one query. Unless you have a really super fast disk subsystem, it might take it a while to retrieve all of that data and process it. Now then, let’s say assume that this table doubles in size each year. Next year, the same query must read 312MB of data just to complete.
Pls refer this link - http://www.datasprings.com/resources/articles-information/key-sql-performance-situations-full-table-scan

The most efficient way to get all data from SQL Server table with varchar(max) column

This question is for SQL Server 2005.
I have a table with 2 columns.
Table_A
Id Guid (PrimaryKey)
TextContent varchar(max)
The table contains around 7000 records and textcontent range from 0 - 150K+.
When I do a select statement
SELECT Id, TextContent FROM Table_A, it took a very long time around 10 minutes.
Is there a better way to get all data out of the table?
During the main execution I only load certain records only. Example: SELECT Id, TextContent FROM TableA WHERE ID IN (#id0,#id1, #id2, #id3....#id20). This query is not slow but not that very fast neither. I want to see if I can optimize the process by pull the TextContent ahead of run time. It is okay for this process to run in a minute or two but 10 minutes is not acceptable.
The GUID is primary key, which is also by default going to be your clustering key no doubt will be causing large fragmentation - but given the nature of the columns, the varchar(max) is going to regularily be off page in the LOB storage and not stored on page unless it fits whilst remaining within the 8060 limit.
So fragmentation is not going to be helped by having a GUID as primary if you also have made it clustered - you can check fragmentation levels using the DMV sys.dm_db_index_physical_stats
I wouldn't think fragmentation is really the problem unless the average amount of data per row is high e.g. regularily above 8k.
If it was,... the fragmentation starts hurting. Worst case is 1 row per page, 7k I/Os which is not ideal, but at 100k average per LOB storage, you could be looking at further 87k I/Os and the order in which the data has been written etc would result in what is supposed to be a sequential scan of the table (and the disk), turning into a massive random I/O fest as the disk heads long stroke back and forth between the page with the row + LOB pointer and the LOB pages.
Added to that is the chance te GUID is the clustering key, so it couldn't even scan the data pages without quite a bit of disk head movement.
I also have to agree with Erich that the quantity of data you are trying to shift across the wire will cause quite a delay on an insufficient link and you should look to properly filter your data at the server level through paging or suitable queries.
I know your looking to pre-cache the data, which can work at times - but it is being performed on such a large entity, it tends to indicate something else is wrong and you are fixing the wrong issue.
A.
This is the correct way to get the data out of the table, unless you only want 1 row. If all you need is 1 row, just use the correct query.
What sort of network connection are you using? Lets put it this way, you have 7000 records. Each contains on average 100k of data (for ease, if it is more or less than this, that's fine, my point still stands). The total query will return 700 MB of data! Even over an extremely fast connection, that is easily 10 minutes of download time.
Even under a PERFECT 100 Megabit connection, the transfer would take nearly a minute! In addition, you have to get that data off of the physical disk, which is going to take a while in addition.
I would recommend doing some sort of paging in order to take the data in smaller bites.
I doubt it. If you want to "get all the data out of the table", then you have to read every byte that is stored within the table, and that may well require a lot of physical disk I/O.
Perhaps what you want is to only retrieve some of the data from the table?
Your Id column is a GUID. Are you using a default? Is it NewID()? I assume it's clustered on the PK.
If you use NewSequentialID() as the default, you'll get fewer page splits, so your data will be spread across fewer physical pages.
With that huge amount of data, that's the only thing I can see that would help the performance.
As many others mentioned, you're fetching a lot of data. First make sure if you need really all rows.
If you do, don't fetch everything at once - use LIMIT instead. This will actually decrease the speed, but if anything fails you'll only have to load a short bit again and don't have to wait another 10 minutes.
SELECT Id, TextContent FROM Table_A LIMIT 0, 30
This query will fetch first 30 entries of your table. With
SELECT Id, TextContent FROM Table_A LIMIT 30, 30
you'll get the next piece.
Maybe you could provide us with a bit more of info, like what you want to do with the data and which programming language you use?
Yes
1)don't use SELECT * ever, always list your columns whether 1, 2 or 100
2)try looking into indexes
150k characters ? in that field ? Is that what you are referring to ?

Cost of Inserts vs Update in SQL Server

I have a table with more than a millon rows. This table is used to index tiff images. Each image has fields like date, number, etc. I have users that index these images in batches of 500. I need to know if it is better to first insert 500 rows and then perform 500 updates or, when the user finishes indexing, to do the 500 inserts with all the data. A very important thing is that if I do the 500 inserts at first, this time is free for me because I can do it the night before.
So the question is: is it better to do inserts or inserts and updates, and why? I have defined a id value for each image, and I also have other indices on the fields.
Updates in Sql server result in ghosted rows - i.e. Sql crosses one row out and puts a new one in. The crossed out row is deleted later.
Both inserts and updates can cause page-splits in this way, they both effectively 'add' data, it's just that updates flag the old stuff out first.
On top of this updates need to look up the row first, which for lots of data can take longer than the update.
Inserts will just about always be quicker, especially if they are either in order or if the underlying table doesn't have a clustered index.
When inserting larger amounts of data into a table look at the current indexes - they can take a while to change and build. Adding values in the middle of an index is always slower.
You can think of it like appending to an address book: Mr Z can just be added to the last page, while you'll have to find space in the middle for Mr M.
Doing the inserts first and then the updates does seem to be a better idea for several reasons. You will be inserting at a time of low transaction volume. Since inserts have more data, this is a better time to do it.
Since you are using an id value (which is presumably indexed) for updates, the overhead of updates will be very low. You would also have less data during your updates.
You could also turn off transactions at the batch (500 inserts/updates) level and use it for each individual record, thus reducing some overhead.
Finally, test this out to see the actual performance on your server before making a final decision.
This isn't a cut and dry question. Krishna's and Galegian's points are spot on.
For updates, the impact will be lessened if the updates are affecting fixed-length fields. If updating varchar or blob fields, you may add a cost of page splits during update when the new value surpasses the length of the old value.
I think inserts will run faster. They do not require a lookup (when you do an update you are basically doing the equivalent of a select with the where clause). And also, an insert won't lock the rows the way an update will, so it won't interfere with any selects that are happening against the table at the same time.
The execution plan for each query will tell you which one should be more expensive. The real limiting factor will be the writes to disk, so you may need to run some tests while running perfmon to see which query causes more writes and causes the disk queue to get the longest (longer is bad).
I'm not a database guy, but I imagine doing the inserts in one shot would be faster because the updates require a lookup whereas the inserts do not.

Resources