YugabyteDB automatically splits user YSQL tables into multiple shards, called tablets, using either a hash– or range– based strategy.
You can see the Tablets for a Table via the admin UI for YB-Master, which is available at http://<<YB-Master IP>>:7000.
We can scrape the information provided from the admin UI and get the details for a particular table.
I’ve encapsulated the logic in a shell script.
#!/bin/bash
shopt -s expand_aliases
# Script: list_tablets.sh
# Description: This script will list tablet details for a given YSQL table by scraping data from
# the YB Master Admin UI. This script uses a user definded SQL function call get_table_id
# which is discussed here: https://yugabytedb.tips/?p=1383
# Created: 11/30/2022
# Last update: 12/01/2022
# Edits:
# 12/01/2022 Added Tablet Row Counts
# 12/02/2022 Check for hash sharded primary key
# Call Spec:
# ./list_tablets.sh < > <> <> <>
# Example Use:
# ./list_tablets.sh public.test 172.152.101.162 yugabyte yugabyte
# Reference: https://docs.yugabyte.com/preview/reference/configuration/yb-master/#admin-ui
# Important Notes:
# 1. Table must have a HASH sharded Primary Key defined
# Verify input parameters
# Check if table name was provided
# Table name must be in the format: schema_name.table_name
if [ -z "$1" ]
then
echo "Please provide a table name in the format: schema_name.table_name"
exit 0
else
YB_SCHEMA_NAME=$(echo $1 | cut -f1 -d.)
YB_TABLE_NAME=$(echo $1 | cut -f2 -d.)
fi
# Check if IP or hostname was provided
if [ -z "$2" ]
then
echo "Please provide an IP or hostname for a YB Master node"
exit 0
else
YB_IP=$2
fi
# Check if table database name was provided
if [ -z "$3" ]
then
echo "Please provide a database name"
exit 0
else
YB_DATABASE=$3
fi
# Check if database user name was provided
if [ -z "$4" ]
then
echo "Please provide a database username"
exit 0
else
YB_USER=$4
fi
# Set up the YSQLSH alias below per your environment
YB_PATH='/home/yugabyte/yb-software/yugabyte-2.15.3.2-b1-linux-x86_64/bin/ysqlsh'
alias y="$YB_PATH -h $YB_IP -U $YB_USER -d $YB_DATABASE"
y1="$YB_PATH -h $YB_IP -U $YB_USER -d $YB_DATABASE"
# Check if table exists
tc=`y -Atc "SELECT COUNT(*) FROM pg_tables WHERE schemaname = '$YB_SCHEMA_NAME' AND tablename = '$YB_TABLE_NAME';" | awk '{ print $1'}`
if [ $tc -gt 0 ]
then
# Get the PK HASH columns for the table.
pk=`y -Atc "WITH q AS (SELECT SUBSTR(pg_catalog.pg_get_indexdef(i.indexrelid, 0, true), POSITION('lsm' IN pg_catalog.pg_get_indexdef(i.indexrelid, 0, true))+4) x FROM pg_catalog.pg_index i JOIN pg_catalog.pg_class c ON c.oid = i.indrelid JOIN pg_catalog.pg_class c2 ON c2.oid = i.indexrelid JOIN pg_catalog.pg_class class ON c.oid = class.oid JOIN pg_catalog.pg_namespace n ON n.oid = class.relnamespace JOIN pg_catalog.pg_constraint con ON (conrelid = i.indrelid AND conindid = i.indexrelid AND contype IN ('p')) WHERE n.nspname = '$YB_SCHEMA_NAME' AND class.relname = '$YB_TABLE_NAME' AND (SUBSTR(pg_catalog.pg_get_indexdef(i.indexrelid, 0, true), POSITION('lsm' IN pg_catalog.pg_get_indexdef(i.indexrelid, 0, true))+4) ILIKE '%HASH,%' OR SUBSTR(pg_catalog.pg_get_indexdef(i.indexrelid, 0, true), POSITION('lsm' IN pg_catalog.pg_get_indexdef(i.indexrelid, 0, true))+4) ILIKE '%HASH\)%') ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname) SELECT REPLACE(REPLACE(x_1, '(', ''), ')', '') FROM (SELECT SUBSTR(x, 1, CASE WHEN POSITION('HASH,' IN x)-1 <= 1 THEN POSITION('HASH)' IN x)-1 ELSE POSITION('HASH,' IN x)-1 END) || ')' x_1 FROM q) foo ORDER BY LENGTH(x_1) DESC LIMIT 1;"`
if [ -z "$pk" ]
then
echo "The table \"$1\" does not have a HASH sharded primary key defined."
exit 1
fi
# Scrap the YB Master UI for Tablet data and print it to the screen
curl -s http://$YB_IP:9000/tablets | grep -A 1 `y -Atc "SELECT get_table_id('$YB_SCHEMA_NAME', '$YB_TABLE_NAME');"` | sed -e 's/<[^>]*>/|/g' | sed 's/\([|]\)\1\+/\1/g' | sed 's:^.\(.*\).$:\1:' | sed -z 's/\n|LEADER/|LEADER/g' | sed '/^$/d' | awk -F\| -v pk="$pk" -v y1="$y1" -v sn="$YB_SCHEMA_NAME" -v tn="$YB_TABLE_NAME" 'BEGIN{print "Tablet ID|Partition|State|Hidden|Row Count|Num SST Files|On-disk size|RaftConfig"}; {p=index($5,","); cmd=y1" -Atc \"SELECT COUNT(*) FROM "sn"."tn" WHERE yb_hash_code("pk") BETWEEN CAST(x\047\""substr($5, p-4, 4)"\"\047 AS INT) AND CAST(x\047\""substr($5, p+4, 4)"\"\047 AS INT);\""; cmd | getline rc; close(cmd); print $4"|"$5"|"$6"|"$7"|"rc"|"$8"|"$9" / "$10" / "$11" / "$12" / "$13"|"$14;}' | column -t -s"|"
else
echo "The table \"$1\" does not exist."
fi
exit 0
Note: The script calls a user defined SQL function to obtain the table ID described here.
Example:
[yugabyte@ip-172-152-101-162 ~]$ alias y
alias y='ysqlsh -h 172.152.101.162'
[yugabyte@ip-172-152-101-162 ~]$ y -c "SELECT COUNT(*) FROM public.test;"
count
-------
40000
(1 row)
[yugabyte@ip-172-152-101-162 ~]$ ./list_tablets.sh public.test 172.152.101.162 yugabyte yugabyte
Tablet ID Partition State Hidden Row Count Num SST Files On-disk size RaftConfig
7b45fa22fa204d6ba90b13ad8e438646 hash_split: [0x0000, 0x5554] RUNNING false 13420 0 Total: 65.00M / Consensus Metadata: 1.5K / WAL Files: 65.00M / SST Files: 0B / SST Files Uncompressed: 0B LEADER: 172.152.101.162
bce09904b78940799c2aca1d91a6dcba hash_split: [0x5555, 0xAAA9] RUNNING false 13372 0 Total: 65.00M / Consensus Metadata: 1.5K / WAL Files: 65.00M / SST Files: 0B / SST Files Uncompressed: 0B LEADER: 172.152.101.162
e092fc5ef6ba44648b786b77d6bc4fc3 hash_split: [0xAAAA, 0xFFFF] RUNNING false 13208 0 Total: 65.00M / Consensus Metadata: 1.5K / WAL Files: 65.00M / SST Files: 0B / SST Files Uncompressed: 0B LEADER: 172.152.101.162
Have Fun!