460 likes | 476 Views
Learn about using hash functions in database management, including hashing principles, hash function types, handling bucket overflows, and extendible hashing techniques.
E N D
Hashing Chapter 11
Static Hashing • A bucket is a unit of storage containing one or more records (a bucket is typically a disk block). • In a hash file organization we obtain the bucket of a record directly from its search-key value using a hashfunction. • Hash function h is a function from the set of all search-key values K to the set of all bucket addresses B. • Hash function is used to locate records for access, insertion as well as deletion. • Records with different search-key values may be mapped to the same bucket; thus entire bucket has to be searched sequentially to locate a record.
Example of Hash File Organization Hash file organization of instructor file, using dept_name as key (See figure in next slide.) • There are 10 buckets, • The binary representation of the ith character is assumed to be the integer i. • The hash function returns the sum of the binary representations of the characters modulo 10 • E.g. h(Music) = 1 h(History) = 2 h(Physics) = 3 h(Elec. Eng.) = 3
Example of Hash File Organization Hash file organization of instructor file, using dept_name as key.
Hash Functions • Worst hash function maps all search-key values to the same bucket; • The access is time proportional to the number of search-key values in the file. • An ideal hash function is uniform, i.e., each bucket is assigned the same number of search-key values from the set of all possible values. • Ideal hash function is random, so each bucket will have the same number of records assigned to it irrespective of the actual distribution of search-key values in the file. • Typical hash functions perform computation on the internal binary representation of the search-key. • For example, for a string search-key, the binary representations of all the characters in the string could be added and the sum modulo the number of buckets could be returned.
Java's hashCode() method s.charAt(0) * 31n-1 + s.charAt(1) * 31n-2 + ... + s.charAt(n-1)
Handling of Bucket Overflows • Bucket overflow can occur because of • Insufficient buckets • Skew in distribution of records. This can occur due to two reasons: • multiple records have same search-key value • chosen hash function produces non-uniform distribution of key values • Although the probability of bucket overflow can be reduced, it cannot be eliminated; it is handled by using overflow buckets.
Handling of Bucket Overflows (Cont.) • Overflow chaining – the overflow buckets of a given bucket are chained together in a linked list. • Above scheme is called closed hashing. • An alternative, called open hashing, which does not use overflow buckets, is not suitable for database applications.
Hash Indices • Hashing can be used not only for file organization, but also for index-structure creation. • A hash index organizes the search keys, with their associated record pointers, into a hash file structure. • Strictly speaking, hash indices are always secondary indices • if the file itself is organized using hashing, a separate primary hash index on it using the same search-key is unnecessary. • However, we use the term hash index to refer to both secondary index structures and hash organized files.
Example of Hash Index hash index on instructor, on attribute ID
Deficiencies of Static Hashing • In static hashing, function h maps search-key values to a fixed set of B of bucket addresses. Databases grow or shrink with time. • If initial number of buckets is too small, and file grows, performance will degrade due to too much overflows. • If space is allocated for anticipated growth, a significant amount of space will be wasted initially (and buckets will be underfull). • If database shrinks, again space will be wasted. • One solution: periodic re-organization of the file with a new hash function • Expensive, disrupts normal operations • Better solution: allow the number of buckets to be modified dynamically.
Extendible Hashing • Situation: Bucket (primary page) becomes full. Why not re-organize file by doubling # of buckets? • Reading and writing all pages is expensive! • Idea: Use directory of pointers to buckets, double # of buckets by doubling the directory, splitting just the bucket that overflowed! • Directory much smaller than file, so doubling it is much cheaper. Only one page of data entries is split. Nooverflowpage! • Trick lies in how hash function is adjusted!
LOCAL DEPTH 2 Example Bucket A 16* 4* 12* 32* GLOBAL DEPTH 2 2 Bucket B 00 5* 1* 21* 13* 01 • Directory is array of size 4. • To find bucket for r, take last `global depth’ # bits of h(r); we denote r by h(r). • If h(r) = 5 = binary 101, it is in bucket pointed to by 01. 2 10 Bucket C 10* 11 2 DIRECTORY Bucket D 15* 7* 19* DATA PAGES • Insert: If bucket is full, splitit (allocate new page, re-distribute). • If necessary, double the directory. (As we will see, splitting a bucket does not always require doubling; we can tell by comparing global depth with local depth for the split bucket.)
Insert h(r)=20 (Causes Doubling) 20 = 101002 2 LOCAL DEPTH 3 LOCAL DEPTH Bucket A 16* 32* 32* 16* GLOBAL DEPTH Bucket A GLOBAL DEPTH 2 2 2 3 Bucket B 5* 21* 13* 1* 00 1* 5* 21* 13* 000 Bucket B 01 001 2 10 2 010 Bucket C 10* 11 10* Bucket C 011 100 2 2 DIRECTORY 101 Bucket D 15* 7* 19* 15* 7* 19* Bucket D 110 111 2 3 Bucket A2 4* 12* 20* DIRECTORY 12* 20* Bucket A2 4* (`split image' of Bucket A) (`split image' of Bucket A)
Points to Note • 20 = binary 10100. Last 2 bits (00) tell us r belongs in A or A2. Last 3 bits needed to tell which. • Global depth of directory: Max # of bits needed to tell which bucket an entry belongs to. • Local depth of a bucket: # of bits used to determine if an entry belongs to this bucket. • When does bucket split cause directory doubling? • Before insert, local depth of bucket = global depth. • Insert causes local depth to become > global depth; directory is doubled by copying it over and `fixing’ pointer to split image page. (Use of least significant bits enables efficient doubling via copying of directory!)
Directory Doubling Why use least significant bits in directory? • Allows for doubling via copying! 6 = 110 6 = 110 3 3 000 000 001 100 2 2 010 010 00 00 1 1 011 110 6* 01 10 0 0 100 001 6* 6* 10 01 1 1 101 101 6* 11 11 6* 6* 110 011 111 111 vs. Least Significant Most Significant
Extendible Hashing: Deletes • If removal of data entry makes bucket empty, can be merged with `split image’. • If each directory element points to same bucket as its split image, can halve directory. • Merging is rarely performed in practiced as data is expected to grow.
Comments on Extendible Hashing • If directory fits in memory, equality search answered with one disk access; else two. • 100MB file, 100 bytes/rec, 4K pages contains 1,000,000 records (as data entries) and 25,000 directory elements; directory fits in memory in most nowadays PCs. • Directory grows in spurts, and, if the distribution of hash values is skewed, directory can grow large. • Multiple entries with same hash value cause problems!
Extendable Hashing vs. Other Schemes • Benefits of extendable hashing: • Hash performance does not degrade with growth of file • Minimal space overhead • Disadvantages of extendable hashing • Extra level of indirection to find desired record • Bucket address table may itself become very big (larger than memory) • Cannot allocate very large contiguous areas on disk either • Solution: B+-tree structure to locate desired record in bucket address table • Changing size of bucket address table is an expensive operation • Linear hashingis an alternative mechanism • Allows incremental growth of its directory (equivalent to bucket address table) • At the cost of more bucket overflows
Linear Hashing • This is another dynamic hashing scheme, an alternative to Extendible Hashing. • LH handles the problem of long overflow chains without using a directory, and handles duplicates. • Idea: Use a family of hash functions h0, h1, h2, ... • hi(key) = h(key) mod(2iN); N = initial # buckets • h is some hash function (range is not 0 to N-1) • If N = 2d0, for some d0, hi consists of applying h and looking at the last di bits, where di = d0 + i. • hi+1 doubles the range of hi (similar to directory doubling)
Linear Hashing (Contd.) • Directory avoided in LH by using overflow pages, and choosing bucket to split round-robin. • Splitting proceeds in `rounds’. • Round ends when all NRinitial (for round R) buckets are split. Buckets 0 to Next-1 have been split; Next to NR yet to be split. • Current round number is Level. • Search:To find bucket for data entry r, findhLevel(r): • If hLevel(r) in range `Next to NR’, r belongs here. • Else, r could belong to bucket hLevel(r) or bucket hLevel(r) + NR; must apply hLevel+1(r) to find out.
Overview of LH File • In the middle of a round. Buckets split in this round: Bucket to be split If ( h search key value ) Level Next is in this range, must use h ( search key value ) Level+1 Buckets that existed at the to decide if entry is in beginning of this round: `split image' bucket. this is the range of h Level `split image' buckets: created (through splitting of other buckets) in this round
Linear Hashing (Contd.) • Insert: Find bucket by applying hLevel / hLevel+1: • If bucket to insert into is full: • Add overflow page and insert data entry. • (Maybe) Split Next bucket and increment Next. • Can choose any criterion to `trigger’ split. • We use bucket overflow! • Since buckets are split round-robin, long overflow chains don’t develop! • Doubling of directory in Extendible Hashing is similar; switching of hash functions is implicit in how the # of bits examined is increased.
Example of Linear Hashing Insert 43* - it triggers split Inset 37* - it does not Insert 29* • On split, hLevel+1 is used to re-distribute entries. Level=0, N=4 Level=0 PRIMARY h h OVERFLOW h h PRIMARY PAGES 0 0 1 1 PAGES PAGES Next=0 32* 32* 44* 36* 000 00 000 00 Next=1 Data entry r 9* 5* 9* 5* 25* 25* with h(r)=5 001 001 01 01 30* 30* 10* 10* 14* 18* 14* 18* Primary 10 10 010 010 bucket page 31* 35* 7* 31* 35* 7* 11* 11* 43* 011 011 11 11 (This info is for illustration only!) (The actual contents of the linear hashed file) 100 44* 36* 00
Example: End of a Round • After inserting: 29. Level=0 PRIMARY OVERFLOW PAGES h PAGES h 1 0 32* 000 00 9* 25* 001 01 Next=2 14* 10 18* 10* 30* 010 43* 11* 7* 31* 35* 011 11 44* 36* 100 00 5* 37* 29* 101 01
Example: End of a Round Level=1 • After adding: 29, 22, 66, 34. PRIMARY OVERFLOW h h PAGES 0 1 PAGES Next=0 Level=0 00 000 32* PRIMARY OVERFLOW PAGES h PAGES h 1 0 001 01 9* 25* 32* 000 00 10 010 50* 10* 18* 66* 34* Insert 50* 9* 25* 001 01 011 11 35* 11* 43* 66* 10 18* 10* 34* 010 Next=3 100 00 44* 36* 43* 11* 7* 31* 35* 011 11 101 11 5* 29* 37* 44* 36* 100 00 14* 22* 30* 110 10 5* 37* 29* 101 01 14* 30* 22* 31* 7* 11 111 110 10
LH Described as a Variant of EH • The two schemes are actually quite similar: • Begin with an EH index where directory has N elements. • Use overflow pages, split buckets round-robin. • First split is at bucket 0. (Imagine directory being doubled at this point.) But elements <1,N+1>, <2,N+2>, ... are the same. So, need only create directory element N, which differs from 0, now. • When bucket 1 splits, create directory element N+1, etc. • So, directory can double gradually. Also, primary bucket pages are created in order. If they are allocated in sequence too (so that finding i’th is easy), we actually don’t need a directory! Voila, LH.
Comparison of Ordered Indexing and Hashing • Cost of periodic re-organization • Relative frequency of insertions and deletions • Is it desirable to optimize average access time at the expense of worst-case access time? • Expected type of queries: • Hashing is generally better at retrieving records having a specified value of the key. • If range queries are common, ordered indices (B+-tree) are to be preferred
Bitmap Indices • Bitmap indices are a special type of index designed for efficient querying on multiple keys • Records in a relation are assumed to be numbered sequentially from, say, 0 • Given a number n it must be easy to retrieve record n • Particularly easy if records are of fixed size • Applicable on attributes that take on a relatively small number of distinct values • E.g. gender, country, state, … • E.g. income-level (income broken up into a small number of levels such as 0-9999, 10000-19999, 20000-50000, 50000- infinity) • A bitmap is simply an array of bits
Bitmap Indices (Cont.) • In its simplest form a bitmap index on an attribute has a bitmap for each value of the attribute • Bitmap has as many bits as records • In a bitmap for value v, the bit for a record is 1 if the record has the value v for the attribute, and is 0 otherwise
Bitmap Indices (Cont.) • Bitmap indices are useful for queries on multiple attributes • not particularly useful for single attribute queries • Queries are answered using bitmap operations • Intersection (and) • Union (or) • Complementation (not) • Each operation takes two bitmaps of the same size and applies the operation on corresponding bits to get the result bitmap • E.g. 100110 AND 110011 = 100010 100110 OR 110011 = 110111 NOT 100110 = 011001 • Query: “Males with income level L1”: • 10010 AND 10100 = 10000 • Can then retrieve required tuples. • Counting number of matching tuples is even faster
Bitmap Indices (Cont.) • Bitmap indices are generally very small compared with relation size • E.g. if record is 100 bytes, space for a single bitmap is 1/800 of space used by relation. • If number of distinct attribute values is 8, bitmap is only 1% of relation size • Deletion needs to be handled properly • Existence bitmapto note if there is a valid record at a record location • Needed for complementation • not(A=v): (NOT bitmap-A-v) AND ExistenceBitmap • Should keep bitmaps for all values, even null value • To correctly handle SQL null semantics for NOT(A=v): • intersect above result with (NOT bitmap-A-Null)
Efficient Implementation of Bitmap Operations • Bitmaps are packed into words; a single word and (a basic CPU instruction) computes and of 32 or 64 bits at once • E.g. 1-million-bit maps can be and-ed with just 31,250 instruction • Counting number of 1s can be done fast by a trick: • Use each byte to index into a precomputed array of 256 elements each storing the count of 1s in the binary representation • Can use pairs of bytes to speed up further at a higher memory cost • Add up the retrieved counts • Bitmaps can be used instead of Tuple-ID lists at leaf levels of B+-trees, for values that have a large number of matching records • Worthwhile if > 1/64 of the records have that value, assuming a tuple-id is 64 bits • Above technique merges benefits of bitmap and B+-tree indices
PostgreSQL supports hash indices, but discourages use due to poor performance • Oracle supports static hash organization, but not hash indices • SQL Server supports only B+-trees
Index Definition in SQL • Create an index create index <index-name> on <relation-name> (<attribute-list>) E.g.: create index b-index on branch(branch_name) • Use create unique index to indirectly specify and enforce the condition that the search key is a candidate key is a candidate key. • Not really required if SQL unique integrity constraint is supported • To drop an index drop index <index-name> • Most database systems allow specification of type of index, and clustering.
Understanding the Workload • For each query in the workload: • Which relations does it access? • Which attributes are retrieved? • Which attributes are involved in selection/join conditions? How selective are these conditions likely to be? • For each update in the workload: • Which attributes are involved in selection/join conditions? How selective are these conditions likely to be? • The type of update (INSERT/DELETE/UPDATE), and the attributes that are affected.
Choice of Indexes • What indexes should we create? • Which relations should have indexes? What field(s) should be the search key? Should we build several indexes? • For each index, what kind of an index should it be? • Clustered? Hash/tree?
Choice of Indexes (Contd.) • One approach:Consider the most important queries in turn. Consider the best plan using the current indexes, and see if a better plan is possible with an additional index. If so, create it. • Obviously, this implies that we must understand how a DBMS evaluates queries and creates query evaluation plans! • For now, we discuss simple 1-table queries. • Before creating an index, must also consider the impact on updates in the workload! • Trade-off:Indexes can make queries go faster, updates slower. Require disk space, too.
Index Selection Guidelines • Attributes in WHERE clause are candidates for index keys. • Exact match condition suggests hash index. • Range query suggests tree index. • Clustering is especially useful for range queries; can also help on equality queries if there are many duplicates. • Multi-attribute search keys should be considered when a WHERE clause contains several conditions. • Order of attributes is important for range queries. • Such indexes can sometimes enable index-onlystrategies for important queries. • For index-only strategies, clustering is not important! • Try to choose indexes that benefit as many queries as possible. Since only one index can be clustered per relation, choose it based on important queries that would benefit the most from clustering.
Examples of Clustered Indexes SELECTE.dno FROMEmp E WHEREE.age>40 • B+ tree index on E.age can be used to get qualifying tuples. • How selective is the condition? • Is the index clustered? • Consider the GROUP BY query. • If many tuples have E.age > 10, using E.age index and sorting the retrieved tuples may be costly. • Clustered E.dno index may be better! • Equality queries and duplicates: • Clustering on E.hobby helps! SELECT E.dno, COUNT (*) FROM Emp E WHERE E.age>10 GROUP BY E.dno SELECT E.dno FROM Emp E WHERE E.hobby=Stamps
Indexes with Composite Search Keys Examples of composite key indexes using lexicographic order. • Composite Search Keys: Search on a combination of fields. • Equality query: Every field value is equal to a constant value. E.g. wrt <sal,age> index: • age=20 and sal =75 • Range query: Some field value is not a constant. E.g.: • age =20; or age=20 and sal > 10 • Data entries in index sorted by search key to support range queries. • Lexicographic order, or • Spatial order. 11,80 11 12 12,10 name age sal 12,20 12 13,75 bob 12 10 13 <age, sal> cal 11 80 <age> joe 12 20 10,12 sue 13 75 10 20 20,12 Data records sorted by name 75,13 75 80,11 80 <sal, age> <sal> Data entries in index sorted by <sal,age> Data entries sorted by <sal>
Composite Search Keys • To retrieve Emp records with age=30 ANDsal=4000, an index on <age,sal> would be better than an index on age or an index on sal. • Choice of index key orthogonal to clustering etc. • If condition is: 20<age<30 AND 3000<sal<5000: • Clustered tree index on <age,sal> or <sal,age> is best. • If condition is: age=30 AND 3000<sal<5000: • Clustered <age,sal> index much better than <sal,age> index! • Composite indexes are larger, updated more often.
Index-Only Plans SELECTE.dno, COUNT(*) FROMEmp E GROUP BY E.dno • A number of queries can be answered without retrieving any tuples from one or more of the relations involved if a suitable index is available. <E.dno> SELECTE.dno, MIN(E.sal) FROMEmp E GROUP BY E.dno <E.dno,E.sal> Tree index! SELECTAVG(E.sal) FROMEmp E WHERE E.age=25 AND E.sal BETWEEN 3000 AND 5000 Tree index!
Index-Only Plans (Contd.) SELECT E.dno, COUNT (*) FROM Emp E WHERE E.age=30 GROUP BY E.dno • Index-only plans are possible if the key is <dno,age> or we have a tree index with key <age,dno> • Which is better? • What if we consider the second query? SELECT E.dno, COUNT (*) FROM Emp E WHERE E.age>30 GROUP BY E.dno
Index-Only Plans (Contd.) <E.dno> SELECT D.mgr FROM Dept D, Emp E WHERE D.dno=E.dno • Index-only plans can also be found for queries involving more than one table; more on this later. <E.dno,E.eid> SELECT D.mgr, E.eid FROM Dept D, Emp E WHERE D.dno=E.dno