How memory distribution happens in vertica plan steps? - query-optimization

I have a situation where a certain vertica query has GROUP_BY_SPILLED in its plan (doing a GROUP BY HASH).
I don't have an option to change the projection order by (to avoid group by hash), so I want to increase the amount of memory this step receives.
Let's say my query received budget of 5GB.
How are the 5GB distributed across the query steps?
I couldn't find any documentation for it.

Take a look at EXECUTION_ENGINE_PROFILES table.
Run your query with PROFILE:
PROFILE SELECT .. FROM .. GROUP BY ..
Grab the statement_id from the output and use it to investigate EXECUTION_ENGINE_PROFILES.
Given a simple query that only does GROUP BY, run:
SELECT path_id,
operator_name,
counter_name,
sum(counter_value)
FROM v_monitor.execution_engine_profiles
WHERE transaction_id=<STATEMENT_ID>
AND counter_name ilike 'current memory capacity (bytes)'
GROUP BY 1,2,3
ORDER BY path_id;
path_id | operator_name | counter_name | sum
---------+---------------+---------------------------------+------------
-1 | NewEENode | current memory capacity (bytes) | 0
-1 | Root | current memory capacity (bytes) | 0
1 | ExprEval | current memory capacity (bytes) | 0
1 | GroupByHash | current memory capacity (bytes) | 1406074880
1 | GroupByPipe | current memory capacity (bytes) | 0
1 | ParallelUnion | current memory capacity (bytes) | 0
1 | StorageUnion | current memory capacity (bytes) | 0
2 | ExprEval | current memory capacity (bytes) | 0
2 | Scan | current memory capacity (bytes) | 0
More info about profiling in Vertica here
I don't think you can modify or improve these counters values, except increasing the query budget using RESOURCE POOLS

Related

Totals for Rows in Cognos 11 Crosstab Report

I am working in Cognos version 11.2.4 and working to attain row totals on a Crosstab report. The table I'm working with has several Locations listed as rows, Hour as columns (24 'Hours'), and count and average time measures. Using the default options to Summarize the columnar data is not an issue - I am able to get a Total for the count column and an overall average for each Average Time column. When attempting to retrieve row summarizations however, I receive an error message:
Error Message
I don't understand the verbiage stating the object selected represents a single value as it should be performing the aggregation on each column for the given row.
My expected results are outlined below:
**Hour 1** **Hour 2**
| Count | Average Time | Count | Average Time | Total | Average |
| -------- | ------------ | -------- | ------------ | ------- | --------- |
Location A| 20 | .5 | 15 | .75 | 35 | .625 |
Location B| 15 | .25 | 25 | .5 | 40 | .375 |
My question is: are the default summary options within Cognos Crosstabs not suitable for row level aggregations?

How to find out Total size of the Hive Database

i have a database with 10 tables. all 10 tables data is stored in different different locations. out of 10 tables, some are managed tables and some are external tables.
some tables location is /apps/hive/warehouse/
some tables location is /warehouse/hive/managed/
some tables location is /warehouse/hive/external/
is there any way to find out total size of the database with out go into each location and find the size, any alternative?
The below query when run in the Hive Metastore DB would help you in getting the total size occupied by all the tables in Hive. Note: The results you get for this query would be 100% correct only if all the tables are having their stats updated. [This can be checked in the table - TABLE_PARAMS in Metastore DB that I have also mentioned below (How it works?.b)]
Steps:
1. Login into Hive Metastore DB and use the database that is used by hive. hive1 by default.
2. Once done, you can execute the below query to get the total size of all the tables in Hive in bytes. The query takes the sum of total size of all the Hive tables based on the statistics of the tables.
MariaDB [hive1]> SELECT SUM(PARAM_VALUE) FROM TABLE_PARAMS WHERE PARAM_KEY="totalSize";
+------------------+
| SUM(PARAM_VALUE) |
+------------------+
| 30376289388684 |
+------------------+
1 row in set (0.00 sec)```
3. Remember, the result derived above is for only one replication. 30376289388684 x 3 is the actual size in HDFS including the replication.
How it works?
a. Selecting a random table in Hive with id 5783 and name - test12345 from the TBLS table in Hive Metastore DB.
MariaDB [hive1]> SELECT * FROM TBLS WHERE TBL_ID=5783;
+--------+-------------+-------+------------------+-------+-----------+-------+-----------+---------------+--------------------+--------------------+----------------+
| TBL_ID | CREATE_TIME | DB_ID | LAST_ACCESS_TIME | OWNER | RETENTION | SD_ID | TBL_NAME | TBL_TYPE | VIEW_EXPANDED_TEXT | VIEW_ORIGINAL_TEXT | LINK_TARGET_ID |
+--------+-------------+-------+------------------+-------+-----------+-------+-----------+---------------+--------------------+--------------------+----------------+
| 5783 | 1555060992 | 1 | 0 | hive | 0 | 17249 | test12345 | MANAGED_TABLE | NULL | NULL | NULL |
+--------+-------------+-------+------------------+-------+-----------+-------+-----------+---------------+--------------------+--------------------+----------------+
1 row in set (0.00 sec)
b. Checking the different parameters of the table in Hive Metastore table - TABLE_PARAMS for the same Hive table with id - 5783. The totalSize record indicates the total size occupied by this table in HDFS for one of its replica. The next point (c) which is the hdfs du -s can be compared to check this.
The param COLUMN_STATS_ACCURATE with the value true says the table's statistics property is set to true. You can check for tables with this value as false to see if there are any tables in Hive those might have missing statistics.
MariaDB [hive1]> SELECT * FROM TABLE_PARAMS
-> WHERE TBL_ID=5783;
+--------+-----------------------+-------------+
| TBL_ID | PARAM_KEY | PARAM_VALUE |
+--------+-----------------------+-------------+
| 5783 | COLUMN_STATS_ACCURATE | true |
| 5783 | numFiles | 1 |
| 5783 | numRows | 1 |
| 5783 | rawDataSize | 2 |
| 5783 | totalSize | 324 |
| 5783 | transient_lastDdlTime | 1555061027 |
+--------+-----------------------+-------------+
6 rows in set (0.00 sec)
c. hdfs du -s output of the same table from HDFS. 324 and 972 are the sizes of one and three replicas of the table data in HDFS.
324 972 /user/hive/warehouse/test12345
Hope this helps!

Can I specify the location of the heap to serialize my data?

I want to store a program state in a file. So I have a mmapped file that I perform operations on and then save it and maybe use it later.
This is fine for simple things but if I want a long lived data structure that requires dynamic memory allocation, I need a memory allocator that I can force to allocate within the pages I have mmapped.
I'm fairly certain I can't do this with the standard c malloc, and I've looked at jemalloc and I don't know if I can see anything there. I don't know if I'm going the wrong way with this, but is there any way to specify the location/size of heap before it is used?
For something like this you don't really want dynamic memory allocation. What you want instead is an array which uses an index value of the pointed to element instead of an actual pointer.
Suppose you wanted to implement a binary tree. You can model it as follows:
struct tree {
int free;
int value;
int left;
int right;
};
The left and right fields contain the indexes of the nodes to the left and to the right of the given node, with the value -1 indicating no such node (i.e. it is equivalent to a NULL pointer in this context).
The free field can be used as a flag to determine whether a given element of the array is currently in use. If a node is marked with free equal to 1, the left field points to the next free node, making it easy to find free nodes.
Node 0 is special in that it is the start of the free list, and the right field points to the root node of the tree.
Then the following tree:
7
/ \
3 10
/ \ / \
1 4 8 12
Can be modeled as follows:
free value left right
---------------------------
0 | 1 | 0 | 8 | 1 |
---------------------------
1 | 0 | 7 | 2 | 3 |
---------------------------
2 | 0 | 3 | 4 | 5 |
---------------------------
3 | 0 | 10 | 6 | 7 |
---------------------------
4 | 0 | 1 | -1 | -1 |
---------------------------
5 | 0 | 4 | -1 | -1 |
---------------------------
6 | 0 | 8 | -1 | -1 |
---------------------------
7 | 0 | 12 | -1 | -1 |
---------------------------
8 | 1 | 0 | 9 | -1 |
---------------------------
9 | 1 | 0 | -1 | -1 |
---------------------------
Such a tree can either be memmapped, or kept in memory using malloc / realloc to manage the size.
If your data structure holds any kind of string, you'll want your structure to contain fixed size character arrays instead of pointers so that they serialize correctly.

Why does Neo4j hit every indexed record when only returning a count?

I am using version 3.0.3, and running my queries in the shell.
I have ~58 million record nodes with 4 properties each, specifically an ID string, a epoch time integer, and lat/lon floats.
When I run a query like profile MATCH (r:record) RETURN count(r); I get a very quick response:
+----------+
| count(r) |
+----------+
| 58430739 |
+----------+
1 row
29 ms
Compiler CYPHER 3.0
Planner COST
Runtime INTERPRETED
+--------------------------+----------------+------+---------+-----------+--------------------------------+
| Operator | Estimated Rows | Rows | DB Hits | Variables | Other |
+--------------------------+----------------+------+---------+-----------+--------------------------------+
| +ProduceResults | 7644 | 1 | 0 | count(r) | count(r) |
| | +----------------+------+---------+-----------+--------------------------------+
| +NodeCountFromCountStore | 7644 | 1 | 0 | count(r) | count( (:record) ) AS count(r) |
+--------------------------+----------------+------+---------+-----------+--------------------------------+
Total database accesses: 0
The Total database accesses: 0 and NodeCountFromCountStore tells me that neo4j uses a counting mechanism here that avoids iterating over all the nodes.
However, when I run profile MATCH (r:record) WHERE r.time < 10000000000 RETURN count(r);, I get a very slow response:
+----------+
| count(r) |
+----------+
| 58430739 |
+----------+
1 row
151278 ms
Compiler CYPHER 3.0
Planner COST
Runtime INTERPRETED
+-----------------------+----------------+----------+----------+-----------+------------------------------+
| Operator | Estimated Rows | Rows | DB Hits | Variables | Other |
+-----------------------+----------------+----------+----------+-----------+------------------------------+
| +ProduceResults | 1324 | 1 | 0 | count(r) | count(r) |
| | +----------------+----------+----------+-----------+------------------------------+
| +EagerAggregation | 1324 | 1 | 0 | count(r) | |
| | +----------------+----------+----------+-----------+------------------------------+
| +NodeIndexSeekByRange | 1752922 | 58430739 | 58430740 | r | :record(time) < { AUTOINT0} |
+-----------------------+----------------+----------+----------+-----------+------------------------------+
Total database accesses: 58430740
The count is correct, as I chose a time value larger than all of my records. What surprises me here is that Neo4j is accessing EVERY single record. The profiler states that Neo4j is using the NodeIndexSeekByRange as an alternative method here.
My question is, why does Neo4j access EVERY record when all it is returning is a count? Are there no intelligent mechanisms inside the system to count a range of values after seeking the boundary/threshold value within the index?
I use Apache Solr for the same data, and returning a count after searching an index is extremely fast (about 5 seconds). If I recall correctly, both platforms are built on top of Apache Lucene. While I don't know much about that software internally, I would assume that the index support is fairly similar for both Neo4j and Solr.
I am working on a proxy service that will deliver results in a paginated form (using the SKIP n LIMIT m technique) by first getting a count, and then iterating over results in chunks. This works really well for Solr, but I am afraid that Neo4j may not perform well in this scenario.
Any thoughts?
The later query does a NodeIndexSeekByRange operation. This is going through all your matched nodes with the record label to look up the value of the node property time and does a comparison if its value is less than 10000000000.
This query actually has to get every node and read some info for comparison, and that's the reason why it is much slower.

MySQL Import into Innodb table severely spikes at a certain point

I'm trying to migrate a 30GB database from one server to another.
The short story is that at a certain point through the process, the amount of time it takes to import records severely increases as a spike. The following is from using the SOURCE command to import a chunk of 500k records (out of about ~25-30 million throughout the database) that was exported as an sql file that was ssh tunnelled over to the new server:
...
Query OK, 2871 rows affected (0.73 sec)
Records: 2871 Duplicates: 0 Warnings: 0
Query OK, 2870 rows affected (0.98 sec)
Records: 2870 Duplicates: 0 Warnings: 0
Query OK, 2865 rows affected (0.80 sec)
Records: 2865 Duplicates: 0 Warnings: 0
Query OK, 2871 rows affected (0.87 sec)
Records: 2871 Duplicates: 0 Warnings: 0
Query OK, 2864 rows affected (2.60 sec)
Records: 2864 Duplicates: 0 Warnings: 0
Query OK, 2866 rows affected (7.53 sec)
Records: 2866 Duplicates: 0 Warnings: 0
Query OK, 2879 rows affected (8.70 sec)
Records: 2879 Duplicates: 0 Warnings: 0
Query OK, 2864 rows affected (7.53 sec)
Records: 2864 Duplicates: 0 Warnings: 0
Query OK, 2873 rows affected (10.06 sec)
Records: 2873 Duplicates: 0 Warnings: 0
...
The spikes eventually average to 16-18 seconds per ~2800 rows affected. Granted I don't usually use Source for a large import, but for the sakes of showing legitimate output, I used it to understand when the spikes happen. Using mysql command or mysqlimport yields the same results. Even piping the results directly into the new database instead of through an sql file has these spikes.
As far as I can tell, this happens after a certain amount of records are inserted into a table. The first time I boot up a server and import a chunk that size, it goes through just fine. Give or take the estimated amount it handles until these spikes occur. I can't correlate that because I haven't consistently replicated the issue to evidently conclude that. There are ~20 tables that have sub 500,000 records that all imported just fine when those 20 tables were imported through a single command. This seems to only happen to tables that have an excessive amount of data. Granted, the solutions I've come cross so far seem to only address the natural DR that occurs when you import over time (The expected output in my case was that eventually at the end of importing 500k records, it would take 2-3 seconds per ~2800, whereas it seems the questions were addressing that at the end it shouldn't take that long). This comes from a single sugarCRM table called 'campaign_log', which has ~9 million records. I was able to import in chunks of 500k back onto the old server i'm migrating off of without these spikes occuring, so I assume this has to do with my new server configuration. Another thing is that whenever these spikes occur, the table that it is being imported into seems to have an awkward way of displaying the # of records via count. I know InnoDB gives count estimates, but the number doesn't succeed the ~, indicating the estimate. It usually is accurate and that each time you refresh the table, it doesn't change the amount it displays (This is based on what it reports through PHPMyAdmin)
Here's the following commands/InnoDB system variables I have on the new server:
INNODB System Vars:
+---------------------------------+------------------------+
| Variable_name | Value |
+---------------------------------+------------------------+
| have_innodb | YES |
| ignore_builtin_innodb | OFF |
| innodb_adaptive_flushing | ON |
| innodb_adaptive_hash_index | ON |
| innodb_additional_mem_pool_size | 8388608 |
| innodb_autoextend_increment | 8 |
| innodb_autoinc_lock_mode | 1 |
| innodb_buffer_pool_instances | 1 |
| innodb_buffer_pool_size | 8589934592 |
| innodb_change_buffering | all |
| innodb_checksums | ON |
| innodb_commit_concurrency | 0 |
| innodb_concurrency_tickets | 500 |
| innodb_data_file_path | ibdata1:10M:autoextend |
| innodb_data_home_dir | |
| innodb_doublewrite | ON |
| innodb_fast_shutdown | 1 |
| innodb_file_format | Antelope |
| innodb_file_format_check | ON |
| innodb_file_format_max | Antelope |
| innodb_file_per_table | OFF |
| innodb_flush_log_at_trx_commit | 1 |
| innodb_flush_method | fsync |
| innodb_force_load_corrupted | OFF |
| innodb_force_recovery | 0 |
| innodb_io_capacity | 200 |
| innodb_large_prefix | OFF |
| innodb_lock_wait_timeout | 50 |
| innodb_locks_unsafe_for_binlog | OFF |
| innodb_log_buffer_size | 8388608 |
| innodb_log_file_size | 5242880 |
| innodb_log_files_in_group | 2 |
| innodb_log_group_home_dir | ./ |
| innodb_max_dirty_pages_pct | 75 |
| innodb_max_purge_lag | 0 |
| innodb_mirrored_log_groups | 1 |
| innodb_old_blocks_pct | 37 |
| innodb_old_blocks_time | 0 |
| innodb_open_files | 300 |
| innodb_print_all_deadlocks | OFF |
| innodb_purge_batch_size | 20 |
| innodb_purge_threads | 1 |
| innodb_random_read_ahead | OFF |
| innodb_read_ahead_threshold | 56 |
| innodb_read_io_threads | 8 |
| innodb_replication_delay | 0 |
| innodb_rollback_on_timeout | OFF |
| innodb_rollback_segments | 128 |
| innodb_spin_wait_delay | 6 |
| innodb_stats_method | nulls_equal |
| innodb_stats_on_metadata | ON |
| innodb_stats_sample_pages | 8 |
| innodb_strict_mode | OFF |
| innodb_support_xa | ON |
| innodb_sync_spin_loops | 30 |
| innodb_table_locks | ON |
| innodb_thread_concurrency | 0 |
| innodb_thread_sleep_delay | 10000 |
| innodb_use_native_aio | ON |
| innodb_use_sys_malloc | ON |
| innodb_version | 5.5.39 |
| innodb_write_io_threads | 8 |
+---------------------------------+------------------------+
System Specs:
Intel Xeon E5-2680 v2 (Ivy Bridge) 8 Processors
15GB Ram
2x80 SSDs
CMD to Export:
mysqldump -u <olduser> <oldpw>, <olddb> <table> --verbose --disable-keys --opt | ssh -i <privatekey> <newserver> "cat > <nameoffile>"
Thank you for any assistance. Let me know if there's any other information I can provide.
I figured it out. I increased the innodb_log_file_size from 5MB to 1024MB. While it did significantly increase the amount of records I imported (Never went above 1 second per 3000 rows), it also fixed the spikes. There were only 2 in all the records I imported, but after they happened, they immediately went back to taking sub 1 second.

Resources