Using Android Room, what is the maximum size of a blob and where is this documented? - android-sqlite

I'm using Android Room and storing ByteArray data as BLOBs. Above a certain size, an attempt to retrieve a row will fail with the following message:
E/CursorWindow: The size of (0, 2) is too big (4194304), so replace the value to NULL
and the actual cause of the crash is:
java.lang.NullPointerException: Parameter specified as non-null is null: method kotlin.jvm.internal.Intrinsics.checkNotNullParameter, parameter bytes
So, above some size the CursorWindow cannot load the blob, returns null, and the DAO method throws NPE because the entity field is not nullable.
I can appreciate that there would be some upper bound on blob size in Sqlite/Room. Experimentally I have determined that it is 4194304 (4096*1024) for my particular setup (at least under certain circumstances).
My questions are: where is this documented? Could it vary by device, Room/Sqlite version, etc/. Can I determine this value at runtime?
I would like to enforce appropriate byte array limits prior to data insertion so this error never occurs, and I am looking for a principled/reliable way to determine the actual limit.
UPDATE
I think #MikeT's answer is the best we can do. The maximum row size we can retrieve using android.database.sqlite is essentially undocumented; most put it at ~2MB but for some reason I (some of the time) peg it at ~4MB using Android 12. Here is a version of #MikeT's answer in Kotlin that should work whether your setup throws an exception on oversized rows or (like mine) returns a null value for the column (which, when using a Room entity with a non-nullable field, will result in a NPE thrown by the dao method).
fun checkCursorWindowSize() {
val context = this
val TEST_TABLE_NAME = "tcw"
val TEST_DATABASE_NAME = "tcw"
val TEST_COLUMN_NAME = "testblob"
val reducer = 1024 * 1024 / 16 /* size to reduce BLOB by per iteration */
val allowance =
1 /* size to reduce BLOB by for all extractions (reason for use probably best to not be on a power of 2 boundary????) */
val ba = ByteArray(1024 * 1024 * 4) /* initial size of BLOB when storing*/
var csr: Cursor
val tcwDbPath: String = context.getDatabasePath(TEST_DATABASE_NAME).getPath()
val dbFile: File = context.getDatabasePath(TEST_DATABASE_NAME)
val dbDirectory: File = dbFile.getParentFile()
/* If the database exists then delete it = should never exist */if (dbFile.exists()) {
dbFile.delete()
}
/* Ensure that the databases directory exists - otherwise openOrCreate fails */if (!dbDirectory.exists()) {
Log.d(
"DEBUGINFO",
"Database directory " + dbDirectory.getPath()
.toString() + " does not exist - Creating"
)
dbDirectory.mkdirs()
}
/* Finally create the database */
val db = SQLiteDatabase.openOrCreateDatabase(tcwDbPath, null, null)
/* Do everything inside a transaction to reduce writes */db.beginTransaction()
/* Create the table into which the BLOB will be loaded */db.execSQL("CREATE TABLE IF NOT EXISTS $TEST_TABLE_NAME ($TEST_COLUMN_NAME BLOB)")
/* Insert the over-sized BLOB */
val cv = ContentValues()
cv.put(TEST_COLUMN_NAME, ba)
db.insert(TEST_TABLE_NAME, null, cv)
/* Prepare to repeatedly extract an eve decreasing part of the blob */
var retrieveSize = ba.size /* first try to retrieve entire BLOB */
var caught = 0 /* the number of caught exceptions */
/* Try 1024 attempts at getting smaller BLOB */
for (i in 0..1024) {
Log.d("DEBUG", "Iteration is " + (i + 1) + ". Retrieve Size is " + retrieveSize)
try {
/* Build the query to extract part of the blob (using the SQLite substr function) according to
the current retrieve size less the allowance
only getting 1 row (should only be 1 row)
NOTE!! retrieving an oversize BLOB does not fail here, rather the failure is when attempting to read the data (getBlob method)
*/
csr = db.query(
TEST_TABLE_NAME,
arrayOf("substr(" + TEST_COLUMN_NAME + ",1," + (retrieveSize - allowance) + ") AS " + TEST_COLUMN_NAME),
null,
null,
null,
null,
null,
"1"
)
var test: ByteArray?=null
while (csr.moveToNext()) {
test = csr.getBlob(0) /* get the Blob from the 1st (only) column */
Log.d("DEBUG", "Received value: ${test?.size}")
}
if (test != null) {
break
}
} catch (e: SQLException) {
caught++
//e.printStackTrace();
} finally {
retrieveSize =
retrieveSize - reducer /* reduce the retrieveSize ready for the next iteration (if one )*/
if (retrieveSize < 0) break
}
}
Log.d("DEBUGINFO", "Caught $caught SQlite Exceptions")
/* Done with the database so clean up */db.endTransaction()
db.close()
File(tcwDbPath).delete()
/* adjust the retrieve size as it has been adjusted in preparation for the next iteration */
Log.d("DEBUGINFO","MaxCursorSize = " + (retrieveSize + reducer).toLong())
}

Your issue is not the maximum size of a BLOB, rather it is the maximum size of a Cursor Window, which is specific to the Android SQLite API/implementation and the limit varies from 1Mb to 4Mb (if I recall correctly) depending upon the version of Android (later Versions having the larger size).
The Cursor Window is wrapped within the Cursor implementation which for Room is wrapped inside the convenience methods, so determining the size, although probably possible would likely be a difficult/complex task.
It is possible to get around the issue, which is that the Cursor Window MUST be able to store a full row (so other columns impact upon how big the Blob itself can be). You can extract parts (chunks) of the Blob and then combine them. Using chunks that are less than 1Mb (probably much less) would cover all limitations.
However, for such large amounts of data, it is recommended to store the data as a file and then store enough of the file path to be able to retrieve the file.
Here's two answers (not using Room though) that retrieve data from a Blob that is greater than the Cursor Window limit.
How to use images in Android SQLite that are larger than the limitations of a CursorWindow?
SQLiteBlobTooBigException still occurs after dividing the request in chunks of 1 MB (and cursor.close())
Do you know how I can determine the limit size for a particular version of Android (or at runtime for the version my app is on)? I found config_cursorWindowSize = 2048 in AOSP code for Android 12 (which is what I'm testing on at the moment), but that's inconsistent with the fact that I've had queries that worked up to about ~4MB per blob (or really, per row, to your point).
The following, from limited testing, (API 28 and 31) is one way BUT I suspect that this may alter (both show 2MB i.e. 2097152) depending upon other uses as CursorWindow can be constructed using a constructor where the windowSize is passed.
Here's the basic/limited java method which
creates a database and a table with just the 1 column into which an oversized BLOB (4Mb) is inserted as the only row,
then progressively tries to extract a smaller part (all at first) of the BLOB until the data can be extracted without the exception
finally it clears up the database
:-
long checkCursorWindowSize(Context context) {
final String TEST_TABLE_NAME = "tcw";
final String TEST_DATABASE_NAME = "tcw";
final String TEST_COLUMN_NAME = "testblob";
final int reducer = 1024 * 1024 / 16; /* size to reduce BLOB by per iteration */
final int allowance = 1; /* size to reduce BLOB by for all extractions (reason for use probably best to not be on a power of 2 boundary????) */
byte[] ba = new byte[1024 * 1024 * 4]; /* initial size of BLOB when storing*/
Cursor csr;
String tcwDbPath = context.getDatabasePath(TEST_DATABASE_NAME).getPath();
File dbFile = context.getDatabasePath(TEST_DATABASE_NAME);
File dbDirectory = dbFile.getParentFile();
/* If the database exists then delete it = should never exist */
if (dbFile.exists()) {
dbFile.delete();
}
/* Ensure that the databases directory exists - otherwise openOrCreate fails */
if (!dbDirectory.exists()) {
Log.d("DEBUGINFO", "Database directory " + dbDirectory.getPath() + " does not exist - Creating");
dbDirectory.mkdirs();
}
/* Finally create the database */
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(tcwDbPath,null,null);
/* Do everything inside a transaction to reduce writes */
db.beginTransaction();
/* Create the table into which the BLOB will be loaded */
db.execSQL("CREATE TABLE IF NOT EXISTS " + TEST_TABLE_NAME + " (" + TEST_COLUMN_NAME + " BLOB)");
/* Insert the over-sized BLOB */
ContentValues cv = new ContentValues();
cv.put(TEST_COLUMN_NAME,ba);
db.insert(TEST_TABLE_NAME,null,cv);
/* Prepare to repeatedly extract an eve decreasing part of the blob */
int retrieveSize = ba.length; /* first try to retrieve entire BLOB */
int caught = 0; /* the number of caught exceptions */
/* Try 1024 attempts at getting smaller BLOB */
for (int i=0; i <= 1024; i++ ) {
Log.d("DEBUG","Iteration is " + (i + 1) + ". Retrieve Size is " + retrieveSize);
try {
/* Build the query to extract part of the blob (using the SQLite substr function) according to
the current retrieve size less the allowance
only getting 1 row (should only be 1 row)
NOTE!! retrieving an oversize BLOB does not fail here, rather the failure is when attempting to read the data (getBlob method)
*/
csr = db.query(TEST_TABLE_NAME, new String[]{"substr(" + TEST_COLUMN_NAME + ",1," + (retrieveSize - allowance) + ") AS " + TEST_COLUMN_NAME},null,null,null,null,null,"1");
while (csr.moveToNext()) {
byte[] test = csr.getBlob(0); /* get the Blob from the 1st (only) column */
}
break; /* if no Exception then all done */
} catch (SQLException e) {
retrieveSize = retrieveSize - reducer; /* reduce the retrieveSize ready for the next iteration (if one )*/
caught++;
//e.printStackTrace();
}
}
Log.d("DEBUGINFO","Caught " + caught + " SQlite Exceptions");
/* Done with the database so clean up */
db.endTransaction();
db.close();
new File(tcwDbPath).delete();
/* adjust the retrieve size as it has been adjusted in preparation for the next iteration */
return retrieveSize + reducer;
}
The limited testing used the following in MainActivity :-
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.d("DEBUGINFO","MaxCursorSize = " + checkCursorWindowSize(this));
}
On API 28 :- D/DEBUGINFO: MaxCursorSize = 2097152
With the whole log being:-
2022-08-29 10:58:06.798 D/DEBUG: Iteration is 16. Retrieve Size is 3211264
2022-08-29 10:58:06.802 W/CursorWindow: Window is full: requested allocation 3211263 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.802 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,3211263) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.802 D/DEBUG: Iteration is 17. Retrieve Size is 3145728
2022-08-29 10:58:06.806 W/CursorWindow: Window is full: requested allocation 3145727 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.807 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,3145727) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.807 D/DEBUG: Iteration is 18. Retrieve Size is 3080192
2022-08-29 10:58:06.810 W/CursorWindow: Window is full: requested allocation 3080191 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.810 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,3080191) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.810 D/DEBUG: Iteration is 19. Retrieve Size is 3014656
2022-08-29 10:58:06.813 W/CursorWindow: Window is full: requested allocation 3014655 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.813 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,3014655) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.813 D/DEBUG: Iteration is 20. Retrieve Size is 2949120
2022-08-29 10:58:06.818 W/CursorWindow: Window is full: requested allocation 2949119 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.819 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2949119) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.819 D/DEBUG: Iteration is 21. Retrieve Size is 2883584
2022-08-29 10:58:06.824 W/CursorWindow: Window is full: requested allocation 2883583 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.824 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2883583) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.825 D/DEBUG: Iteration is 22. Retrieve Size is 2818048
2022-08-29 10:58:06.829 W/CursorWindow: Window is full: requested allocation 2818047 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.829 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2818047) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.829 D/DEBUG: Iteration is 23. Retrieve Size is 2752512
2022-08-29 10:58:06.832 W/CursorWindow: Window is full: requested allocation 2752511 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.832 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2752511) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.832 D/DEBUG: Iteration is 24. Retrieve Size is 2686976
2022-08-29 10:58:06.837 W/CursorWindow: Window is full: requested allocation 2686975 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.838 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2686975) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.838 D/DEBUG: Iteration is 25. Retrieve Size is 2621440
2022-08-29 10:58:06.842 W/CursorWindow: Window is full: requested allocation 2621439 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.842 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2621439) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.842 D/DEBUG: Iteration is 26. Retrieve Size is 2555904
2022-08-29 10:58:06.846 W/CursorWindow: Window is full: requested allocation 2555903 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.846 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2555903) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.846 D/DEBUG: Iteration is 27. Retrieve Size is 2490368
2022-08-29 10:58:06.849 W/CursorWindow: Window is full: requested allocation 2490367 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.849 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2490367) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.849 D/DEBUG: Iteration is 28. Retrieve Size is 2424832
2022-08-29 10:58:06.853 W/CursorWindow: Window is full: requested allocation 2424831 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.853 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2424831) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.854 D/DEBUG: Iteration is 29. Retrieve Size is 2359296
2022-08-29 10:58:06.857 W/CursorWindow: Window is full: requested allocation 2359295 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.858 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2359295) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.858 D/DEBUG: Iteration is 30. Retrieve Size is 2293760
2022-08-29 10:58:06.862 W/CursorWindow: Window is full: requested allocation 2293759 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.862 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2293759) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.862 D/DEBUG: Iteration is 31. Retrieve Size is 2228224
2022-08-29 10:58:06.865 W/CursorWindow: Window is full: requested allocation 2228223 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.865 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2228223) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.865 D/DEBUG: Iteration is 32. Retrieve Size is 2162688
2022-08-29 10:58:06.870 W/CursorWindow: Window is full: requested allocation 2162687 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.870 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2162687) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.870 D/DEBUG: Iteration is 33. Retrieve Size is 2097152
2022-08-29 10:58:06.874 W/CursorWindow: Window is full: requested allocation 2097151 bytes, free space 2096720 bytes, window size 2097152 bytes
2022-08-29 10:58:06.875 E/SQLiteQuery: exception: Row too big to fit into CursorWindow requiredPos=0, totalRows=1; query: SELECT substr(testblob,1,2097151) AS testblob FROM tcw LIMIT 1
2022-08-29 10:58:06.875 D/DEBUG: Iteration is 34. Retrieve Size is 2031616
2022-08-29 10:58:06.881 D/DEBUGINFO: Caught 33 SQlite Exceptions
2022-08-29 10:58:06.904 D/DEBUGINFO: MaxCursorSize = 2097152
On API 31 the result is exactly the same bar the time/timings i.e. MaxCursorSize is calculated returned as 2097512
However, add another column for example and then other data has to be loaded into the CursorWindow and the result is then not a true reflection of how big the Blob can be.
hence why it could well just lead to issues if any reliance were made on the limit of what a CursorWindow can hold in total.

Related

How to determine how much space 1 row will take in Postgres db?

I'm very new to Postgres so my math could be off here...
This is my table:
CREATE TABLE audit (
id BIGSERIAL PRIMARY KEY,
content_id VARCHAR (50) NULL,
type VARCHAR (100) NOT NULL,
size bigint NOT NULL,
timestamp1 timestamp NOT NULL DEFAULT NOW(),
timestamp2 timestamp NOT NULL DEFAULT NOW());
I want to make some estimations on how much space 1 row would occupy. So I did something like this:
1 row = id + content_id + type + size + timestamp1 + timestamp2
= 8 + 100 + 50 + 8 + 8 + 8 bytes
= 182 bytes
I also created this same table in my local postgres but the numbers are not matching
INSERT INTO public.audit(
content_id, type, size)
VALUES ('aaa', 'bbb', 100);
SELECT pg_size_pretty( pg_total_relation_size('audit') ); -- returns 24 kb
INSERT INTO public.audit(
content_id, type, size)
VALUES ('aaaaaaaaaaaaa', 'bbbbbbbbbbbbbb', 100000000000);
SELECT pg_size_pretty( pg_total_relation_size('audit') ); -- still returns 24 kb
Which brings me to think that Postgres reserves a space of 24 kb to start with and as I put in more data it will get incremented by 132 bytes once I go beyond 24 kb? But something inside me says that can't be right.
I want to see how much space 1 row would occupy in Postgres db so I can analyze how much data I can potentially store in it.
Edit
After reading more I've come up with this, is it correct?
1 row =
23 (heaptupleheader)
+ 1 (padding)
+ 8 (id)
+ 50 (content_id)
+ 6 (padding)
+ 100 (type)
+ 4 (padding)
+ 8 (size)
+ 8 (timestamp)
+ 8 (timestamp)
= 216 bytes
That "something inside me says that can't be right" is wrong. Actually trying id determine the size of each row is impractical. You can calculate the average row, and given a large number of rows the better that average get. Part of that reason is variable length columns. Your definition varchar(50) does not required bytes of storage unless unless it contains 50 bytes, if it has 20 then it only takes up 20 bytes (plus overhead), even then it's not exact as the padding may change. The definition only specifies the Maximum not the actual, storage is on actual.
As far a your 24kb that doesn't seem out-of-line at all. Keep in mind that physical I/O is the slowest possible individual operation and trying to adjust to individual rows for I/O would bring your system to a screeching halt. Postgres therefore only reads in full blocks (and allocates space the same), and/or multiple blocks. Typically with a block size of 8K (8192 bytes). This is the trade off I/O performance vs. space allocation. It appears your system has a multi-block read of 3 blocks (??). If anything is surprising it would that is is that small.
In short trying to get the size of a row not piratical, instead get several hundred representative rows and calculate the average.
BTW you can change the length just by rearranging your columns:
1 row =
23 (heaptupleheader)
+ 1 (padding)
+ 8 (id)
+ 8 (size)
+ 8 (timestamp)
+ 8 (timestamp)
+ 50 (content_id)
+ 2 (padding) (if content contains all 50 char)
+ 100 (type) (if type contains all 100 char)
= 208 bytes

How to calculate size of tables which are saved on disk? (PosgreSQL)

How to calculate size of tables which are saved on disk?
Based on my internet searching, how to calculate the length of the table based on the formula:
8KB × ceil(number of records / floor(floor(8KB × fillfactor - 24) / (28 + data length of 1 record)))
Example:
Column | Type |
aid | integer |
bid | integer |
abalance | integer |
filler | character(84) |
data length of 1 record = aid(4 bytes) + bid(4 bytes) + abalance(4 bytes) + filler(84 bytes + 1 byte) = 97 byte
The data length of a record must be rounded to 8 bytes.
=> Data length of 1 record is 104 bytes.
Therefore, I think that 1 character is contained in 1 byte of memory.
However, column "filler" can be input with 84 characters "a" (single byte) or 84 characters "あ" (double-byte)
I don’t know why double-byte character can be contained in single byte character?
Can you explain to me this question?
It's much simpler. Use pg_relation_size to calculate the size of one relation alone (without the associated TOAST tables and indexes) or pg_total_relation_size to include all associated objects.

How to group sql range query by clause

I am receiving a error while building the index. I recently switched to PostgreSQL and I am using Navicat. The error is coming from the Locations table that has the zip code, city, state, latitude and longitude.
indexing index 'location_core'...
collected 84068 docs, 0.7 MB
sorted 0.1 Mhits, 100.0% done
total 84068 docs, 716268 bytes
total 0.686 sec, 1043676 bytes/sec, 122495.78 docs/sec
indexing index 'user_core'...
ERROR: index 'user_core': sql_range_query: ERROR: column "locations.latitude" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: ...sers"."updated_at")::int AS "updated_at", RADIANS(locations....
^
(DSN=pgsql://lexi87:***#localhost:5432/dating_development).
total 0 docs, 0 bytes
total 0.007 sec, 0 bytes/sec, 0.00 docs/sec
indexing index 'user_delta'...
ERROR: index 'user_delta': sql_range_query: ERROR: column "locations.latitude" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: ...sers"."updated_at")::int AS "updated_at", RADIANS(locations....
How exactly can I put them in a group by clause? Any help would be appreciated!

delete row key from cassandra cli

i set my column family gcgraceseconds to 0;
but stills rowkey is not deleted it remains in my column family
create column family workInfo123
with column_type = 'Standard'
and comparator = 'UTF8Type'
and default_validation_class = 'UTF8Type'
and key_validation_class = 'UTF8Type'
and read_repair_chance = 0.1
and dclocal_read_repair_chance = 0.0
and populate_io_cache_on_flush = true
and gc_grace = 0
and min_compaction_threshold = 4
and max_compaction_threshold = 32
and replicate_on_write = true
and compaction_strategy = 'org.apache.cassandra.db.compaction.SizeTieredCompactionStrategy'
and caching = 'KEYS_ONLY'
and default_time_to_live = 0
and speculative_retry = 'NONE'
and compression_options = {'sstable_compression' : 'org.apache.cassandra.io.compress.LZ4Compressor'}
and index_interval = 128;
see below the view of
[default#winoriatest] list workInfo123;
Using default limit of 100
Using default cell limit of 100
-------------------
RowKey: a
-------------------
RowKey: xx
2 Rows Returned.
Elapsed time: 17 msec(s).
i am using cassandra -cli
should i have change anything else
UPDATE:-
after using ./nodetool -host 127.0.0.1 compact
[default#winoriatest] list workInfo123;
Using default limit of 100
Using default cell limit of 100
-------------------
RowKey: xx
2 Rows Returned.
Elapsed time: 11 msec(s).
why xx remains ??
When you delete a row in Cassandra, it does not get deleted straight away. Instead it is marked with a tombstone. The effect is, that you still get a result for the key, but no columns will be delivered. The tombstone is required because
Cassandra data files become read-only once they are "full"; the tombstone is added to the currently open data file containing the deleted row.
you have to give the cluster a chance to propagate the delete to all nodes holding a copy of the row.
For the row and its tombstone to be removed a compaction is required. This process re-organizes the data files and while it does that, it prunes deleted rows. That is, if the GC grace period of the tombstone has been reached. For single-node(!) clusters it is OK to set the grace period to 0 because the delete does not have to be propagated to any other node (that might be down at the point in time you issued the delete).
If you want to enforce the removal of deleted rows, you can trigger a flush (sync memory with data files) and a major compaction via the nodetool utility. E.g.
./nodetool flush your_key_space the_column_family && ./nodetool compact your_key_space the_column_family
After the compaction completes, the deleted rows should truly be gone.
Default GC grace period is ten days(means 846000 sec) in order to remove the rowkey immediately
UPDATE COLUMN FAMILY column_family_name with GC_GRACE= 0;
execute the above cli query follow the nodetool flush and compact operation.

how to check table is using how much space in DB2

Is there a way in DB2 to identify that a table is consuming how much of the total space allocated to the underlying table space."
Thanks
DB2 queries to check the table size
select
a.CARD*(sum(b.AVGCOLLEN)+10)/1024/1024 as Tablesize_in_MB
from
syscat.tables as a, syscat.columns as b
where
a.TABNAME = b.TABNAME and b.TABNAME = 'TABLE_NAME' group by a.CARD
data size
select
char(date(t.stats_time))||' '||char(time(t.stats_time)) as statstime
,substr(t.tabschema,1,8)||'.'||substr(t.tabname,1,24) as tabname
,card as rows_per_table
,decimal(float(t.npages)/ ( 1024 / (b.pagesize/1024)),9,2) as used_mb
,decimal(float(t.fpages)/ ( 1024 / (b.pagesize/1024)),9,2) as allocated_mb
from
syscat.tables t , syscat.tablespaces b
where t.tbspace=b.tbspace
order by 5 desc with ur
index size
select
rtrim(substr(i.tabschema,1,8))||'.'||rtrim(substr( i.tabname, 1,24)) as tabname
,decimal(sum(i.nleaf)/( 1024 / (b.pagesize/1024)),12,2) as indx_used_per_table_mb
from
syscat.indexes i, syscat.tables t , syscat.tablespaces b
where
i.tabschema is not null and i.tabname=t.tabname
and i.tabschema=t.tabschema and t.tbspace=b.tbspace
group by
i.tabname,i.tabschema, b.pagesize order by 2 desc with ur
Your question creates a false dichotomy because a tablespace may be created without allocating a limited amount of space to it. The limitation may rather be the drive or share that the tablespace is on. But if you know the space allocated to a tablespace or only need the percent of a tablespace's current size that a table is using, then yes, there is a way to know.
SELECT * FROM SYScat.tables where tabname='mytable';
will tell you how many pages a table is using.
Then at the command line: LiST TABLESPACES SHOW DETAIL
will tell you how many total pages are in the tablespace and the size of a page in bytes.
Select * from sysibmadm.tbsp_utilization where tbsp_name='MyTblSpace'
will give you the maximum size of the tablespace if it has one.
You can get the underlying table physical size from the SYSIBMADM.ADMINTABINFO table.
The command is given below.
db2 "SELECT SUBSTR(TABSCHEMA,1,15) as SCHEMA, SUBSTR(TABNAME,1,20) as
TABLENAME, DATA_OBJECT_P_SIZE ,INDEX_OBJECT_P_SIZE ,
LONG_OBJECT_P_SIZE , LOB_OBJECT_P_SIZE , XML_OBJECT_P_SIZE,
(DATA_OBJECT_P_SIZE + INDEX_OBJECT_P_SIZE + LONG_OBJECT_P_SIZE +
LOB_OBJECT_P_SIZE + XML_OBJECT_P_SIZE ) as TOTAL_P_SIZE from
SYSIBMADM.ADMINTABINFO where TABNAME='table_name'"
The total physical size is the sum of all the DATA , INDEX, LONG , LOB and XML OBJECT physical sizes (_P_SIZE indicates Physical Size).
You cannot get the tablespace name(even though you could get the tablespace id) from SYSIBMADM.ADMINTABINFO, for that you need to join the above query with SYSCAT.TABLES.