Showing posts with label Mysql Primary Key. Show all posts
Showing posts with label Mysql Primary Key. Show all posts

Monday, 25 November 2019

HOW IMPORTANT A PRIMARY KEY CAN BE FOR MYSQL PERFORMANCE?

How important a primary key design can be for MySQL performance? The answer is: Extremely! If tables use InnoDB storage engine, that is.
It all begins with the specific way InnoDB organizes data internally. There are two major pieces of information that anyone should know:
  1. It physically stores rows together with and in the order of primary key values. It means that a primary key does not only uniquely identify a row, it is also part of it. Or perhaps rather, a physical row is part of table's primary key.
  2. A secondary index entry does not point to the actual row position, which is how it works in MyISAM. Instead, every single index entry is concatenated with a value of the corresponding primary key. When a query reads a row through a secondary index, this added value is used in additional implicit lookup by the primary key, to locate the actual row.
What could be a "rule of the thumb" for InnoDB primary key design is that it should be as short as possible. Needlessly long values use a lot of space inside the secondary indexes and may degrade performance.
It is also good when primary key is also incremental, i.e. each new row has a value there that is larger than in any other existing row. This does not necessarily imply AUTO_INCREMENT column, which is just one of the possibilities. Because rows are kept in the order of the key, using values that constantly grow means InnoDB may simply "append" rows to a table. It benefits insert performance and prevents fragmentation as data does not have to be moved around to make room for an insert that needs to add a row in the middle of table.
However in some cases it turns out that choosing a simple, short and incremental column for primary key is not the best option when thinking about database scalability. With certain access patterns, especially when reads by range are prevalent, it turns out that longer and more complex design can produce better results in the longer term.
When AUTO_INCREMENT column becomes primary key, rows are placed one after another in the order of insertion. If two rows were added at the interval of 1 hour to a table receiving a constant stream of inserts, there would likely be some physical distance between both of them. I.e. they would be in two different places on disk as many other rows would be added in between these two.
For the sake of example let's assume two rows were added for a user whose user_id is 50 and they have been assigned with id=10000000 and id=10001000, where id is the primary key in this table. What sort of work the following query has to perform in order to return results?
SELECT * FROM messages WHERE user_id = 50
It finds index entires where user_id is 50. With the primary key values from the secondary index, it can then locate the physical rows. So InnoDB first seeks a row where id is 10000000. But since it does not operate on individual rows at this point, but rather on the blocks of records called pages, it locates the proper page on disk and caches it in the buffer pool. Only then it can extract the actual row, return it, and move on to the next one where id is 10001000. Since the distance between the two records is significant, it turns out that it is not on the same page that was just pulled into the cache and which holds the first row. InnoDB has to go back to disk to fetch another page, cache it, extract the row and return it.
In the above example at least two I/Os were issued. In a pessimistic case for a few hundred matching rows, when a user has that many messages, that could result in a few hundred I/O operations. Random I/O. Assuming as little as a few milliseconds for each operation, the query may need as much as one second to execute. It would use index properly, it would only pull a few hundred rows, but would still perform poorly. With the exception for flash technology any typical storage is rather slow, and also very difficult to scale, so such scenario should be avoided.
Another negative effect, which could be further affecting MySQL performance, is buffer pool pollution. If application asks for a hundred rows and each of them resides on a different page, InnoDB will need to load one hundred pages that may be irrelevant to all other queries. When the buffer is full, loading anything new into it means dropping some of the existing information. That way InnoDB cache may fill with a lot of data that isn't actually needed.
What if the primary key was different?
For example a composite key on pair of columns (user_id, id). In such case every row sharing common value in user_id would be stored next to each other. In other words, all messages belonging to a single user would be kept together on one or maybe just a few pages. How would the example query execute now?
SELECT * FROM messages WHERE user_id = 50
Execution begins the same way, however after finding the first matching row, it turns out the other row that the query is looking for is actually on the same page that was loaded into the buffer pool just a moment earlier. So instead of two I/O operations, one was enough. What if there were a few hundred rows to read? One or maybe a few reads instead of hundreds. That is a significant gain.
Additional gain is that the query no longer needs to do the extra lookup through the secondary index and with the lower overhead it can execute even faster. Querying InnoDB tables by primary key values is faster, which is different from MyISAM where it does not matter for performance whether access is by primary or secondary keys.
More? Improved data locality not only improves this query performance. It also allows more efficient use of memory, which results in caching more relevant information and thus improves overall MySQL performance.
Why (user_id, id)? Using user_id alone would not be possible, because primary key enforces uniqueness, while each user may have many rows. With id being a unique incremental column also some inserts may still see improved performance. For example if application inserted ten rows all for the same user, they would possibly be stored on a single page.
When designing an InnoDB table you have to think ahead. None of this matters when database is small, but it can make a tremendous difference once data grows sufficiently. Unfortunately many solutions, which developers use to build applications, completely miss this. Out of many frameworks I know, very few even support composite primary keys through their CRUD modules. On the other hand, thanks to this performance consultants have so much work ;-)

Can MySQL use primary key values from a secondary index?


In the article about the role of a primary key, I mentioned that a secondary index in an InnoDB table consists not only of the values of its member columns, but also values of the table's primary key are concatenated to the index. I.e. the primary key contents is part of every other index.
Assuming the following table structure:
CREATE TABLE `bets` (
  `id` int(10) unsigned NOT NULL,
  `user_id` int(10) unsigned NOT NULL,
  `game_id` int(10) unsigned NOT NULL,
...
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`)
) ENGINE=InnoDB

If MySQL could use in queries these implicitly added values, it would maybe allow to save some space on listing the primary key columns at the end of an index explicitly. Let's check various cases.
Row filtering
mysql> EXPLAIN
    -> SELECT *
    -> FROM   bets
    ->        JOIN games
    ->        ON     games.id = bets.id
    -> WHERE  bets.user_id = 111
    ->        AND bets.id > 3476G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: bets
         type: ref
possible_keys: user_id
          key: user_id
      key_len: 4
          ref: const
         rows: 22
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: games
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: game.bets.id
         rows: 1
        Extra: 
Both key_len and ref fields indicate that only one four bytes long column is used from the user_id index. MySQL cannot use the primary key values in a secondary index for filtering in WHERE clause.
Sorting with ORDER BY
mysql> EXPLAIN
    -> SELECT   *
    -> FROM     bets
    ->          JOIN games
    ->          ON       games.id = bets.game_id
    -> WHERE    bets.user_id = 111
    -> ORDER BY bets.id DESCG
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: bets
         type: ref
possible_keys: user_id
          key: user_id
      key_len: 4
          ref: const
         rows: 22
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: games
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: game.bets.game_id
         rows: 1
        Extra: 
Extra only returns Using where, but there is no Using filesort. It means ORDER BY will be optimized using the hidden primary key data from the secondary index.
Aggregating with GROUP BY
mysql> EXPLAIN
    -> SELECT   *
    -> FROM     bets
    ->          JOIN games
    ->          ON       games.id = bets.game_id
    -> WHERE    bets.user_id = 111
    -> GROUP BY bets.idG
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: bets
         type: ref
possible_keys: user_id
          key: user_id
      key_len: 4
          ref: const
         rows: 22
        Extra: Using where
*************************** 2. row ***************************
           id: 1
  select_type: SIMPLE
        table: games
         type: eq_ref
possible_keys: PRIMARY
          key: PRIMARY
      key_len: 4
          ref: game.bets.game_id
         rows: 1
        Extra: 
Also in this case Extra neither shows Using filesort nor Using temporary, which would indicate no index is used for grouping. Therefore MySQL can optimize GROUP BY on the concatenated primary key values.
Covering index
mysql> EXPLAIN
    -> SELECT bets.id
    -> FROM   bets
    -> WHERE  bets.user_id = 111G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: bets
         type: ref
possible_keys: user_id
          key: user_id
      key_len: 4
          ref: const
         rows: 22
        Extra: Using index
The query execution plan confirms through Using index that it will only need index contents to return result. MySQL can read and return the hidden primary key values to avoid the additional data lookup.
Summary
In InnoDB tables each entry of a secondary index always contains a copy of the corresponding primary key value. These values may in some cases be used to the benefit of query execution plan:
  • for ORDER BY on the primary key column(s)
  • for GROUP BY on the primary key column(s)
  • when returning the primary key column(s) values in the SELECT list
MySQL cannot use them, however, to optimize filtering in WHERE.

Tuesday, 6 November 2018

Foreign key referring to primary keys across multiple tables?

I have to two tables namely employees_ce and employees_sn under the database employees.
They both have their respective unique primary key columns.
I have another table called deductions, whose foreign key column I want to reference to primary keys of employees_ce as well as employees_sn. Is this possible?
for example
employees_ce
--------------
empid   name
khce1   prince

employees_sn
----------------
empid   name
khsn1   princess
so is this possible?
deductions
--------------
id      name
khce1   gold
khsn1   silver

 Answers


Assuming that I have understood your scenario correctly, this is what I would call the right way to do this:
Start from a higher-level description of your database! You have employees, and employees can be "ce" employees and "sn" employees (whatever those are). In object-oriented terms, there is a class "employee", with two sub-classes called "ce employee" and "sn employee".
Then you translate this higher-level description to three tables: employeesemployees_ce and employees_sn:
  • employees(id, name)
  • employees_ce(id, ce-specific stuff)
  • employees_sn(id, sn-specific stuff)
Since all employees are employees (duh!), every employee will have a row in the employees table. "ce" employees also have a row in the employees_ce table, and "sn" employees also have a row in the employees_sn table. employees_ce.id is a foreign key to employees.id, just as employees_sn.id is.
To refer to an employee of any kind (ce or sn), refer to the employees table. That is, the foreign key you had trouble with should refer to that table!



Actually I do this myself. I have a table called 'Comments' which contains comments for records in 3 other tables. Neither solution actually handles everything you probably want it to. In your case, you would do this:
Solution 1:
  1. Add a tinyint field to employees_ce and employees_sn that has a default value which is different in each table (This field represents a 'table identifier', so we'll call them tid_ce & tid_sn)
  2. Create a Unique Index on each table using the table's PK and the table id field.
  3. Add a tinyint field to your 'Deductions' table to store the second half of the foreign key (the Table ID)
  4. Create 2 foreign keys in your 'Deductions' table (You can't enforce referential integrity, because either one key will be valid or the other...but never both:
    ALTER TABLE [dbo].[Deductions]  WITH NOCHECK ADD  CONSTRAINT [FK_Deductions_employees_ce] FOREIGN KEY([id], [fk_tid])
    REFERENCES [dbo].[employees_ce] ([empid], [tid])
    NOT FOR REPLICATION 
    GO
    ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_ce]
    GO
    ALTER TABLE [dbo].[Deductions]  WITH NOCHECK ADD  CONSTRAINT [FK_Deductions_employees_sn] FOREIGN KEY([id], [fk_tid])
    REFERENCES [dbo].[employees_sn] ([empid], [tid])
    NOT FOR REPLICATION 
    GO
    ALTER TABLE [dbo].[Deductions] NOCHECK CONSTRAINT [FK_600_WorkComments_employees_sn]
    GO
    
    employees_ce
    --------------
    empid    name     tid
    khce1   prince    1
    
    employees_sn
    ----------------
    empid    name     tid 
    khsn1   princess  2
    
    deductions
    ----------------------
    id      tid       name  
    khce1   1         gold
    khsn1   2         silver         
    ** id + tid creates a unique index **
    
Solution 2: This solution allows referential integrity to be maintained: 1. Create a second foreign key field in 'Deductions' table , allow Null values in both foreign keys, and create normal foreign keys:
    employees_ce
    --------------
    empid   name
    khce1   prince 

    employees_sn
    ----------------
    empid   name     
    khsn1   princess 

    deductions
    ----------------------
    idce    idsn      name  
    khce1   *NULL*    gold
    *NULL*  khsn1     silver         
Integrity is only checked if the column is not null, so you can maintain referential integrity.



Technically possible. You would probably reference employees_ce in deductions and employees_sn. But why don't you merge employees_sn and employees_ce? I see no reason why you have two table. No one to many relationship. And (not in this example) many columns.
If you do two references for one column, an employee must have an entry in both tables.



Assuming you must have two tables for the two employee types for some reason, I'll extend on vmarquez's answer:
Schema:
employees_ce (id, name)
employees_sn (id, name)
deductions (id, parentId, parentType, name)
Data in deductions:
deductions table
id      parentId      parentType      name
1       1             ce              gold
2       1             sn              silver
3       2             sn              wood
...
This would allow you to have deductions point to any other table in your schema. This kind of relation isn't supported by database-level constraints, IIRC so you'll have to make sure your App manages the constraint properly (which makes it more cumbersome if you have several different Apps/services hitting the same database).

Friday, 2 November 2018

Differences between INDEX, PRIMARY, UNIQUE, FULLTEXT in MySQL?

What are the differences between PRIMARY, UNIQUE, INDEX and FULLTEXT when creating MySQL tables?
How would I use them?

 Answers


Differences

  • KEY or INDEX refers to a normal non-unique index. Non-distinct values for the index are allowed, so the index may contain rows with identical values in all columns of the index. These indexes don't enforce any restraints on your data so they are used only for making sure certain queries can run quickly.
  • UNIQUE refers to an index where all rows of the index must be unique. That is, the same row may not have identical non-NULL values for all columns in this index as another row. As well as being used to speed up queries, UNIQUE indexes can be used to enforce restraints on data, because the database system does not allow this distinct values rule to be broken when inserting or updating data.
    Your database system may allow a UNIQUE index to be applied to columns which allow NULL values, in which case two rows are allowed to be identical if they both contain a NULL value (the rationale here is that NULL is considered not equal to itself). Depending on your application, however, you may find this undesirable: if you wish to prevent this, you should disallow NULL values in the relevant columns.
  • PRIMARY acts exactly like a UNIQUE index, except that it is always named 'PRIMARY', and there may be only one on a table (and there should always be one; though some database systems don't enforce this). A PRIMARY index is intended as a primary means to uniquely identify any row in the table, so unlike UNIQUE it should not be used on any columns which allow NULL values. Your PRIMARY index should be on the smallest number of columns that are sufficient to uniquely identify a row. Often, this is just one column containing a unique auto-incremented number, but if there is anything else that can uniquely identify a row, such as "countrycode" in a list of countries, you can use that instead.
    Some database systems (such as MySQL's InnoDB) will store a table's records on disk in the order in which they appear in the PRIMARY index.
  • FULLTEXT indexes are different from all of the above, and their behaviour differs significantly between database systems. FULLTEXT indexes are only useful for full text searches done with the MATCH() / AGAINST() clause, unlike the above three - which are typically implemented internally using b-trees (allowing for selecting, sorting or ranges starting from left most column) or hash tables (allowing for selection starting from left most column).
    Where the other index types are general-purpose, a FULLTEXT index is specialised, in that it serves a narrow purpose: it's only used for a "full text search" feature.

Similarities

  • All of these indexes may have more than one column in them.
  • With the exception of FULLTEXT, the column order is significant: for the index to be useful in a query, the query must use columns from the index starting from the left - it can't use just the second, third or fourth part of an index, unless it is also using the previous columns in the index to match static values. (For a FULLTEXT index to be useful to a query, the query must use all columns of the index.)



I feel like this has been well covered, maybe except for the following:
  • Simple KEY / INDEX (or otherwise called SECONDARY INDEX) do increase performance if selectivity is sufficient. On this matter, the usual recommendation is that if the amount of records in the result set on which an index is applied exceeds 20% of the total amount of records of the parent table, then the index will be ineffective. In practice each architecture will differ but, the idea is still correct.
  • Secondary Indexes (and that is very specific to mysql) should not be seen as completely separate and different objects from the primary key. In fact, both should be used jointly and, once this information known, provide an additional tool to the mysql DBA: in Mysql, indexes embed the primary key. It leads to significant performance improvements, specifically when cleverly building implicit covering indexes such as described there
  • If you feel like your data should be UNIQUE, use a unique index. You may think it's optional (for instance, working it out at application level) and that a normal index will do, but it actually represents a guarantee for Mysql that each row is unique, which incidentally provides a performance benefit.
  • You can only use FULLTEXT (or otherwise called SEARCH INDEX) with Innodb (In MySQL 5.6.4 and up) and Myisam Engines
  • You can only use FULLTEXT on CHARVARCHAR and TEXT column types
  • FULLTEXT index involves a LOT more than just creating an index. There's a bunch of system tables created, a completely separate caching system and some specific rules and optimizations applied. See http://dev.mysql.com/doc/refman/5.7/en/fulltext-restrictions.html and http://dev.mysql.com/doc/refman/5.7/en/innodb-fulltext-index.html

Wednesday, 31 October 2018

Mysql: Database Skills: A Sane Approach To Choosing Primary Keys

Welcome to the Database Programmer. This blog is for anyone who wants to learn about databases, both simple and advanced. Since all non-trivial websites require a database, and since database skills are different from coding skills, there is very good reason for any programmer to master the principles of database design and use

There is no One True Primary Key

There are several competing theories out there on how to choose primary keys. Most of them tell you to use a single kind of key for all tables, usually an integer. In contrast to those theories I have found that a robust application uses different kinds of keys for different kinds of tables. In the last 15 years I have worked on projects large and small, simple and complex. Sometimes I had total technical control, and sometimes I had to work with what others gave me, and sometimes it was a little of both. Today's essay reflects what I have worked out in those years, and how I build my tables today. My goal is to report what actually works, not to promote a particular theory about how everybody should do something.
This week we will see "rules of thumb". A rule of thumb is a guiding idea that will tend to hold true most of the time, but which you may decide to change in certain circumstances.

Rule of Thumb 1: Use Character Keys For Reference Tables

A reference table is one that tends to be strongly constant over time and has relatively few columns. Sometimes a reference table may come already populated by the programmer. Examples include tables of country codes (perhaps with international telephone prefixes), a table of provinces or states within a country, or a table of timezones. In this series I have been using the example of a school management program, for that program we might give the user a reference table of school subjects like history, math, physics and so forth.
For these tables it is best to make a character primary key, which we often call a "code", as in "timezone code" or "country code" or "subject code." The strategy is to make a code which can be used on its own as a meaningful value that people can understand. This gives us tables that are easier to use for both programmer and end-user.
Let's consider our school management program. We have a table of teachers (populated by the school staff), and a table of subjects which we have provided as a reference table. When a teacher joins the faculty, somebody must enter the subjects that that teacher is qualified to each. The tables below show two examples of what this table might look like, which is easier to read?
TEACHER - SUBJECT CROSS REFERENCE

EXAMPLE 1: INTEGER KEYS           EXAMPLE 2: CHARACTER KEYS

Teacher | Subject                 Teacher     |  Subject
--------+----------               ------------+-----------
72      | 28                      SRUSSEL     |  PHYSICS
72      | 32                      SRUSSEL     |  CALCULUS
72      | 72                      SRUSSEL     |  HISTORY
45      | 28                      ACLAYBORNE  |  PHYSICS
45      | 29                      ACLAYBORNE  |  CELLBIOLOGY
45      | 45                      ACLAYBORNE  |  RUSSIAN
The table of character keys is much easier to work with, for the simple reason that many times you can just use the codes themselves, so you can avoid a lot of JOINs to the main tables. With integers you must always JOIN to the master table so you can get a meaningful value to show the user. But not only is the table itself easier to read when you are debugging, it is easier to work with when writing queries:
-- The character key example is pretty simple:
SELECT teacher,subject FROM teachers_x_subjects

-- The integer key absolutely requires joins
SELECT x.teacher_id,x.subject_id
       t.name,s.description
  FROM teachers_x_subjects x
  JOIN teachers t ON x.teacher_id = t.teacher_id
  JOIN subjects s ON x.subject_id = s.subject_id
I often hear people say they do not like SQL because it is so complicated and they hate doing so many JOINs. It makes me wonder if the person is lost in a JOIN jungle caused by very bad advice about always using integer primary keys.
If you are using some kind of ORM system that tries to protect you from coding any SQL, that basic problem of over-complicated tables will still appear in your code. One way or another you must enter details that tell the ORM system how to get the descriptions, which would not be necessary if the keys were meaningful character values.
We can now see the surprising fact that the integer keys will slow us down in many situations. Not only do they have no performance advantage, but they actually hurt performance. The reason is because they require joins on almost every query. A 3-table query with two joins will always be much slower than a 1-table query with no joins. If you are using an ORM system that does not do JOIN's, but instead does separate fetches, then you have 3 round trips to the server instead of 1, and heaven forbid you have queries in a nested loop, the performance will simply crash and burn. All of this is kind of ironic since you so often hear people blindly repeat the dogmatic phrase "We will use integer keys for performance reasons..."

Rule of Thumb 2: Use Character Keys for Small Master Tables

Many database programmers use the term "master table" to mean any table that lists the properties of things that have some permanence, like customers, teachers, students, school subjects, countries, timezones, items (skus), and anything else that can be listed once and used many times in other places. Generally a master table has more columns than a simple reference table.
Some master tables are small and do not change often. In our ongoing example of a school management application, the list of teachers is a good example of a small master table. Compared to the list of students, which is much larger and changes every year, the table of teachers at most schools (except for huge state universities) will have only a few changes each year.
For tables like this it is good to allow the user to enter character keys if they want to. Some schools will insist on being allowed to choose their own codes like 'SRUSSEL' for "Saxifrage Russel", while others will say, "Why should I have to make up a code, can't the computer do that?"
For these tables I have found it useful to always define the primary key as a character column, and then to allow some flexibility in how it is generated. Common ways of generating codes include:
  1. Letting the user make up their own code
  2. Generating a code out of some other column or columns, like first letter of first name, plus 5 letters of last name, plus three numeric digits. (This used to be very popular in decades past).
  3. Generate a number.
The key idea here is to follow the needs of your users. Option #2 above is one of the most useful because it gives you the best of both worlds.

Rule of Thumb 3: Use Integers For Large Master Tables

Some master tables are large or they change often, or both. In our ongoing example of a school management application, the list of students will change every year, with many students coming and going. Another example is a doctor's office that has patients coming and going all of the time. I have found it best to use plain integer keys here because:
  • Unlike small master tables (like teachers) or reference tables (like school subjects), a code is not likely to have any meaning for the end-user, so the biggest argument for using it does not hold.
  • Unlike reference tables, the master table is likely to have many more columns and you will probably end up JOINing to the table many times. This means our other big reason for using codes, which is to avoid JOINs, does not hold either.
  • It is not realistic to expect end-users to be making up codes for large tables, and since the codes will have no value, why should the end-user be troubled with the job?
  • Writing algorithms to generate unique codes will run into more difficulties, and since the code has no value why bother?

Rule of Thumb 4: Use Integers For Transaction Tables

Many database programmers use the term "transaction table" to mean any kind of table that records some kind of interaction or event between master tables. In an eCommerce program the shopping cart tables are all transaction tables, they record the purchase of items by customers. In our school management program the actual classes taken by students are transactions, because they record specific interactions between students and teachers.
For these tables the auto-generated integer key tends to be the most useful. I am not going to present any arguments for this because most programmers find it self-evident. It should be enough to say that any attempt to use a compound key (like customer + date ) always ends up causing a problem by limiting what can be entered, so the meaningless integer key is the way to go.

Rule of Thumb 5: Use Multi-Column Keys In Cross References

A useful database will end up with a lot of cross reference tables in it. A cross-reference table is any table that lists various facts about how master tables relate to each other. These tables are extremely useful for validating transactions. In fact, next week's entry will be all about these tables and how to use them.
For now the important point is that the primary key of a cross-reference is a combination of the foreign keys. We do not make up an extra column, either integer or character.
TEACHER-SUBJECT CROSS REFERENCE

Teacher     |  Subject
------ -----+-------------
SRUSSEL     |  PHYSICS
SRUSSEL     |  CALCULUS
SRUSSEL     |  HISTORY
ACLAYBORNE  |  PHYSICS
ACLAYBORNE  |  CELLBIOLOGY
ACLAYBORNE  |  RUSSIAN
The SQL for this table would resemble something like this:
CREATE TABLE teachers_x_subjects (
    teacher char(10)
   ,subject char(10)
   ,primary key (teacher,subject)
   ,foreign key (teacher) references teachers(teacher)
   ,foreign key (subject) references subjects(subject)
)
The reasons for this are rather complex, and next week the entire entry will be devoted to this and similar ideas. For now we will note that this approach lets us validate teacher-class assignments so that no teacher is assigned to teach a class she is not qualified for. Using a new column as a primary key does not allow that, and therefore leads to more complicated and error-prone code.

Rule of Thumb 6: Use Given Keys For Non-Insert Imports

Many systems today that we create will interact with systems that already exist. A typical eCommerce program will get a list of items and maybe even customers from the company's main computer system.
For some of these tables, your own system will absolutely never make new rows. A very common example is a table of items on an eCommerce site that is loaded up from some other computer system.
For these tables, the simplest route is to use whatever key exists on the table as it is given to you. Any other route involves more work with no clear motivation for putting out the effort.

Rule of Thumb 7: Use Integer Keys for Import/Export Tables

Sometimes you may have a table whose original values come from another system, but unlike the previous case your own system is generating new rows for the table, and you may have to send these rows back to the original system.
One classic example of this is a list of customers. I created a website a few years ago where the list of customers is updated from a different system from time-to-time. However, new customers can also sign up online. Both systems are handing the customer list back and forth from time to time to keep them reconciled.
In these cases I have an integer primary key for the table because it follows Rule of Thumb 3, it is a large master table. The most important concept here is that you must not try to combine your key and the key from the original table. Keep the key from the original table in its own column, index on it, and use it for updates, but do not try to enforce it as a unique column. The other system must take care of its own key, and your system must take care of yours.

Rule of Thumb 8: Use An Object Id On All Tables

Back when people were getting excited about the concept of "Object-Relational Databases", they came up with the term "object id" to denote a column that contains some unique value but otherwise has no meaning. The same idea exists with different names, but Object ID is now the term that most people understand so that is the term I will use.
Your programs can be made simpler in many cases if you add an object id to every single table in addition to the primary key. An object id is useful specifically for user interface code. If you use an object id, then it is easier to write UPDATE and DELETE statements, and it is easier to write framework or ORM code that does these things for you.
If you are following these rules of thumb closely in your project then it is important not to use the object id as a primary key, and therefore you may never use it as a foreign key either. If you use an object id as the primary key then you lose a lot of the benefits of the character keys listed above.
Also if you follow these rules in your projects it means that your transaction tables have both an auto-generated primary key like CART_ID and an auto-generated object id. Some programmers are bothered by this because we don't like the idea that two columns appear to be doing the same thing, and we try to save a column. But personally this does not bother me because it helps me write robust applications, and this is not 1985 where a 10MB hard drive cost hundreds of dollars.

Absolute Rule 1: Only Atomic Values

This is not merely a "rule of thumb" but a rule that I follow absolutely. It is actually part of First Normal Form, which is that column values must be atomic, or indivisible. Another way to say it is that the column must not have "subvalues" buried in it.
I have included this rule here instead of with First Normal Form because when most programmers violate this rule they are making primary keys by combining different values together. In our example of a school program, if we have a list of the actual students taking classes in a given school year, you might have a squashed-up primary key column like this:
CLASS_CODE                | STUDENT
--------------------------+---------------
SRUSSEL-2007-PHYSICS      | NAI
SRUSSEL-2007-MATH         | PCLAYBORNE
ACLAYBORNE-2007-RUSSIAN   | JBOONE
ACLAYBORNE-2007-MATH      | NAI
There are two practical problems with doing this:
  1. You cannot use a foreign key to validate the sub-values, so you must code validation manually.
  2. Retrieving the sub-values requires extra code, either in the SELECT or in your client code. If the values were in separate columns this would not be necessary.

Absolute Rule 2: No Magic Values

Another rule that I follow is to absolutely never have magic values. A magic value is a value in a column that causes some non-obvious result. I have included this is in this essay because most programmers who break this rule do so by hard-coding special actions to occur based on values of keys in reference tables and master tables.
An example might be a table of teachers, where one of the teacher values is something like "SUBSTITUTE", and the program is hardcoded to do a lot of different things when it sees this value. Magic values are bad because the code is harder to debug. It may not be obvious to a programmer that some special value of the TEACHER column would cause special actions to occur. But if you have a column called FLAG_SUBSTITUTE then any programmer who must maintain code written by somebody else will have a much easier time of it.
Magic numbers also confuse end-users. It may seem obvious to us that the value "SUBSTITUTE" in the teacher column means substitute, but if this value causes other things to occur, and we are in the regular habit of having these values in lots of tables, then the compound effect can be lots and lots of phone calls from confused users, and big trouble for the software developer's bottom line.
Finally, magic numbers limit you. If you use the value "SUBSTITUTE" as a single teacher in the teachers file, then how do you keep track of the dozen-odd substitutes the school may hire in a year? The end-user is stuck here, they must use pen and paper. It is much better to allow them to enter the substitute as a regular faculty member with a FLAG_SUBSTITUE column to check off.
Magic numbers have plagued programming since long before databases came around. 

Conclusion: Many Kinds of Tables, Many Kinds of Keys

This week we have seen that there can be many practical benefits to using different kinds of keys for different kinds of tables. Using the right kind of key for the right kind of table leads to simpler code and better performance, whether you code SQL directly or use an ORM system.
Remember always that your application will always follow the same structure as your tables. If the tables are designed well, the code will be lean, tight, efficient, and robust. Because table design is so important, it is best to know well the different kinds of tables there are: reference, master, cross-reference, and transaction, and to build the keys wisely.

Monday, 29 October 2018

Mysql: set existing column as Primary Key in MySQL

I have a database with 3 columns:
id, name, somethingelse  
This table has no index set and i am getting "No index defined!" in phpmyadmin
id is a 7digit alphanumeric value, unique to each row.
I want to set Drugid to be the primarykey/index (i dont know the difference if there is one)

 Answers


Either run in SQL:
ALTER TABLE tableName
  ADD PRIMARY KEY (id)           ---or Drugid, whichever you want it to be PK
or use the PHPMyAdmin interface (Table Structure)



If you want to do it with phpmyadmin interface:
Select the table -> Go to structure tab -> On the row corresponding to the column you want, click on the icon with a key



Go to localhost/phpmyadmin and press enter key. Now select database --> table_name --->Structure --->Action ---> Primary -->click on Primary

Wednesday, 24 October 2018

Create a MySQL table with a primary key

A primary key uniquely identify a row in a table. One or more columns may be identified as the primary key. The values in a single column used as the primary key must be unique (like a person’s social security number). When more than one column is used, the combination of column values must be unique.

When creating the contacts table described in Create a basic MySQL table, the column contact_id can be made a primary key using PRIMARY KEY(contact_id) as with the following SQL command:
CREATE TABLE `test1` ( contact_id INT(10),
name VARCHAR(40),
birthdate DATE,
PRIMARY KEY (contact_id)
);
Additional columns can be identified as part of the primary key with a comma separated list in the PRIMARY KEY command, like PRIMARY KEY (contact_id, name).

Tuesday, 2 June 2015

Mysql: Select N rows before and after the matching row

Table definition:
CREATE TABLE languages(
  id INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  name VARCHAR(20) NOT NULL,
  PRIMARY KEY (language_id)
);

Populate table:
INSERT INTO languages VALUES
  (1, 'English'),
  (5, 'Italian'),
  (10, 'Japanese'),
  (11, 'Mandarin'),
  (21, 'French'),
  (25, 'German'),
  (30, 'Spanish'),
  (32, 'Turkish');

Find the matching row and its nearest records - 2 before and 2 after:
SELECT id, name FROM (
  SELECT
    l.*,
    @i:=@i + 1 rank,
    @match:=IF(l.name = 'French', @i, @match)
  FROM
    languages l,
    (SELECT @i:=0, @match:=0) vars
  ORDER BY
    l.id
) t
WHERE
  @match >= rank - 2 AND @match <= rank + 2;
+----+----------+
| id | name     |
+----+----------+
| 10 | Japanese |
| 11 | Mandarin |
| 21 | French   |
| 25 | German   |
| 30 | Spanish  |
+----+----------+